singrdk/base/Windows/MutexWrap/mutexwrap.c

224 lines
5.7 KiB
C
Raw Normal View History

2008-03-05 09:52:00 -05:00
// ----------------------------------------------------------------------------
//
// Program: MutexWrap
//
// Purpose: This wrapper opens a named mutex and then runs a
// user specified process holding the mutex. The mutex is
// relinquished when the program stops executing.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
#define _WIN32_WINNT 0x0500
#include <winlean.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ACQUIRE_TIMEOUT 1000
#define HOLD_TIMEOUT 1001
// #define VERBOSE
#ifdef VERBOSE
#define tprintf(x,...) printf(x, __VA_ARGS__)
#else
#define tprintf(x,...)
#endif
static HANDLE g_hMutex = NULL;
static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
{
tprintf("Caught control event %I32u", dwCtrlType);
switch (dwCtrlType) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
GenerateConsoleCtrlEvent(dwCtrlType, 0);
default:
break;
}
if (NULL != g_hMutex) {
ReleaseMutex(g_hMutex); // May not be acquired
CloseHandle(g_hMutex);
}
ExitProcess((UINT)-2);
}
static BOOL
ParseDWord(LPCSTR lpszValue, PDWORD pValue)
{
PCHAR pszStop;
errno = 0;
*pValue = strtoul(lpszValue, &pszStop, 10);
// Return no overflow and all characters parsed.
return errno == 0 && *pszStop == '\0';
}
static void Usage()
{
printf(
"Usage:\n" \
"mutexwrap [options] <mutexname> <command>\n\n" \
"Runs <command> holding named mutex. Waits up to specifiable timeout to \n" \
"acquire the mutex, and potentially timeouts command.\n\n" \
"The available options are:\n" \
" /WaitTime <seconds> - Set limit on time waited to acquire mutex.\n" \
" /HoldTime <seconds> - Set limit on time process runs for.\n" \
"The process returns 0 on success, %d on mutex acquisition failure, %d on\n" \
"process run time exceeded.\n\n" \
"Example:\n mutexwrap /w 10 /h 10 MyMutex \"sleep.exe 500\"\n"
,
ACQUIRE_TIMEOUT, HOLD_TIMEOUT
);
}
static void
ErrorReport(char *function)
{
VOID *message;
DWORD error = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &message, 0, NULL);
fprintf(stderr, "%s failed with error %d: %s\n", function, error, message);
LocalFree(message);
}
static DWORD
SecondsToMillis(DWORD dwSeconds)
{
if (dwSeconds > INFINITE / 1000) {
return INFINITE;
}
return dwSeconds * 1000;
}
static DWORD RunProcess(LPCSTR lpCommandLine, DWORD dwHoldSeconds)
{
DWORD dwExitCode = HOLD_TIMEOUT;
DWORD dwHoldMillis = INFINITE;
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, (LPSTR)lpCommandLine, NULL, NULL, FALSE,
0, NULL, NULL, &si, &pi)) {
fprintf(stderr, "mutexwrap: Failed to create process: \"%s\"\n",
lpCommandLine);
ErrorReport("CreateProcess");
return (DWORD)-1;
}
dwHoldMillis = SecondsToMillis(dwHoldSeconds);
if (WaitForSingleObject(pi.hProcess, dwHoldMillis) == WAIT_OBJECT_0) {
GetExitCodeProcess(pi.hProcess, &dwExitCode);
}
else {
fprintf(stderr,
"mutexwrap: timed out holding mutex with program running.");
TerminateProcess(pi.hProcess, (DWORD)-1);
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return dwExitCode;
}
static BOOL
AcquireMutex(HANDLE hMutex, DWORD dwTimeoutSeconds)
{
time_t nowTime;
time_t endTime;
time(&endTime);
endTime += dwTimeoutSeconds;
while (time(&nowTime) < endTime) {
DWORD dwWaitMillis = INFINITE;
if (endTime - nowTime < INFINITE * 1000i64) {
dwWaitMillis = (DWORD)((endTime - nowTime) * 1000);
}
if (WaitForSingleObject(hMutex, dwWaitMillis) == WAIT_OBJECT_0) {
return TRUE;
}
}
fprintf(stderr, "mutexwrap: timed out acquiring mutex.\n");
return FALSE;
}
int main(int argc, LPCSTR argv[])
{
DWORD dwWaitSeconds = INFINITE;
DWORD dwHoldSeconds = INFINITE;
DWORD dwExitCode = 0;
argv++;
argc--;
while (argc > 0 && (argv[0][0] == '/' || argv[0][0] == '-')) {
if (tolower(argv[0][1]) == 'w' && argc > 2) {
if (!ParseDWord(argv[1], &dwWaitSeconds)) {
fprintf(stderr, "mutexwrap: Invalid wait time.\n");
return -1;
}
}
else if (tolower(argv[0][1]) == 'h' && argc > 2) {
if (!ParseDWord(argv[1], &dwHoldSeconds)) {
fprintf(stderr, "mutexwrap: Invalid hold time.\n");
return -1;
}
}
else {
Usage();
return -1;
}
argv += 2;
argc -= 2;
}
tprintf("Wait time %us, Hold time %us\n", dwWaitSeconds, dwHoldSeconds);
if (argc != 2) {
Usage();
return -1;
}
SetConsoleCtrlHandler(CtrlHandler, TRUE);
if (NULL == (g_hMutex = CreateMutex(NULL, FALSE, argv[0]))) {
fprintf(stderr, "mutexwrap: failed to create mutex.\n");
ErrorReport("CreateMutex");
return -1;
}
argc--;
argv++;
if (AcquireMutex(g_hMutex, dwWaitSeconds)) {
dwExitCode = RunProcess(argv[0], dwHoldSeconds);
ReleaseMutex(g_hMutex);
}
else {
dwExitCode = ACQUIRE_TIMEOUT;
}
CloseHandle(g_hMutex);
return dwExitCode;
}