singrdk/base/Windows/RunAll/runall.c

231 lines
6.5 KiB
C
Raw Normal View History

2008-03-05 09:52:00 -05:00
// ----------------------------------------------------------------------------
//
// Program: RunAll
//
// Purpose: Run all processes simultaneously with optional fatal error
// on any process failure or timeout. This is intended to be
// used by the automated build process to wrapper running
// bootd and the kernel debugger side-by-side.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
#define _WIN32_WINNT 0x0500
#include <winlean.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static BOOL g_bVerbose = FALSE;
#define tprintf if (g_bVerbose) printf
static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
{
printf("Caught control event %I32u", dwCtrlType);
switch (dwCtrlType) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
GenerateConsoleCtrlEvent(dwCtrlType, 0);
default:
break;
}
ExitProcess((UINT)-2);
}
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 );
printf("runall: %s failed with error %d: %s",
function, error, message);
LocalFree(message);
}
void usage()
{
printf("Usage: runall [options] cmd [cmd1] ...\n\n");
printf("Options:\n");
printf(" /T:seconds - Set timeout in seconds.");
printf("Runs specified commands in parallel and wait for all to terminate successfully. The program returns -1 if any process fails to launch, or exits with a non zero error-code, or the option timeout expires.");
}
static BOOL
ParseInt64(LPCSTR lpszValue, PINT64 pValue)
{
PCHAR pszStop;
errno = 0;
*pValue = _strtoi64(lpszValue, &pszStop, 10);
// Return no overflow and all characters parsed.
return errno == 0 && *pszStop == '\0';
}
static int
RunAndWait(int nProcesses,
LPPROCESS_INFORMATION lpProcessInfo,
LPCSTR lpszCommandLine[],
time_t endTime)
{
HANDLE hProcesses[MAXIMUM_WAIT_OBJECTS];
int nProcessOrdinal[MAXIMUM_WAIT_OBJECTS];
int i;
for (i = 0; i < nProcesses; i++) {
if (ResumeThread(lpProcessInfo[i].hThread) == -1) {
ErrorReport("ResumeThread");
return -1;
}
hProcesses[i] = lpProcessInfo[i].hProcess;
nProcessOrdinal[i] = i;
}
while (nProcesses > 0) {
DWORD dwMilliseconds;
DWORD dwResult;
time_t t;
time(&t);
if (t > endTime) {
printf("runall: timeout\n");
return -1;
}
t = (endTime - t) / 1000;
dwMilliseconds = (DWORD)((t < INFINITE) ? t : INFINITE - 1);
dwResult = WaitForMultipleObjects(nProcesses,
hProcesses,
FALSE,
dwMilliseconds);
if (dwResult == WAIT_TIMEOUT) {
}
else if (dwResult >= WAIT_ABANDONED_0 &&
dwResult <= WAIT_ABANDONED_0 + nProcesses) {
printf("runall: wait abandoned (process %d)\n",
dwResult - WAIT_ABANDONED_0);
return -1;
}
else {
DWORD dwProcess = dwResult - WAIT_OBJECT_0;
DWORD dwExitCode;
hProcesses[dwProcess] = hProcesses[--nProcesses];
nProcessOrdinal[dwProcess] = nProcessOrdinal[nProcesses];
if (GetExitCodeProcess(hProcesses[dwProcess], &dwExitCode) == 0) {
ErrorReport("GetExitCodeProcess");
return -1;
}
printf("runall: Command \"%s\" => exited %d\n",
lpszCommandLine[nProcessOrdinal[dwProcess]],
dwExitCode);
if (dwExitCode != 0) {
return -1;
}
}
}
return 0;
}
static int
RunAll(int nProcesses, LPCSTR lpszCommandLine[], time_t endTime)
{
PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
STARTUPINFO si;
int exitCode = -1;
int i;
for (i = 0; i < nProcesses; i++) {
DWORD dwCreationFlags = CREATE_SUSPENDED | CREATE_NO_WINDOW;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcess(NULL, (LPSTR)lpszCommandLine[i], NULL, NULL, FALSE,
dwCreationFlags, NULL, NULL, &si, &pi[i])) {
ErrorReport("CreateProcess");
break;
}
tprintf("runall: Created PID %u: %s\n",
pi[i].dwProcessId, lpszCommandLine[i]);
}
if (i == nProcesses) {
exitCode = RunAndWait(nProcesses, pi, lpszCommandLine, endTime);
}
while (--i >= 0) {
if (TerminateProcess(pi[i].hProcess, -1)) {
tprintf("runall: Terminated PID %u: %s\n",
pi[i].dwProcessId, lpszCommandLine[i]);
}
}
return exitCode;
}
int
main(int argc, LPCSTR argv[])
{
BOOL bLaunchFailure = FALSE;
time_t endTime = _I64_MAX;
INT64 timeout = 0;
argc--;
argv++;
while (argc != 0 && (argv[0][0] == '/' || argv[0][0] == '-')) {
switch (tolower(argv[0][1])) {
case 't':
if (argv[0][2] == ':' && ParseInt64(&argv[0][3], &timeout)) {
time(&endTime);
endTime += (time_t)timeout;
}
else {
printf("Bad timeout argument.");
return -1;
}
break;
case 'v':
g_bVerbose = TRUE;
break;
default:
usage();
return -1;
}
argc --;
argv ++;
}
if (argc == 0) {
usage();
return -1;
} else if (argc > MAXIMUM_WAIT_OBJECTS) {
printf("Supported process limit exceeded.");
return -1;
}
SetConsoleCtrlHandler(CtrlHandler, TRUE);
return RunAll(argc, argv, endTime);
}