Commit 0753862e authored by Brad King's avatar Brad King

ENH: Windows implementation of process pipeline.

parent 4a60a24b
......@@ -89,10 +89,21 @@ kwsysEXPORT void kwsysProcess_Delete(kwsysProcess* cp);
/**
* Set the command line to be executed. Argument is an array of
* pointers to the command and each argument. Ths array must end with
* a NULL pointer.
* a NULL pointer. Any previous command lines are removed. Returns
* 1 for success and 0 otherwise.
*/
kwsysEXPORT void kwsysProcess_SetCommand(kwsysProcess* cp,
char const* const* command);
kwsysEXPORT int kwsysProcess_SetCommand(kwsysProcess* cp,
char const* const* command);
/**
* Add a command line to be executed. Argument is an array of
* pointers to the command and each argument. Ths array must end with
* a NULL pointer. If this is not the first command added, its
* standard input will be connected to the standard output of the
* previous command. Returns 1 for success and 0 otherwise.
*/
kwsysEXPORT int kwsysProcess_AddCommand(kwsysProcess* cp,
char const* const* command);
/**
* Set the timeout for the child process. The timeout period begins
......
......@@ -27,6 +27,8 @@ PURPOSE. See the above copyright notices for more information.
#include <windows.h>
#include <stdio.h>
void ReportLastError(HANDLE errorPipe);
int main()
{
/* Process startup information for the real child. */
......@@ -49,6 +51,11 @@ int main()
/* Handle to the error reporting pipe provided by the parent. This
is parsed off the command line. */
HANDLE errorPipe = 0;
HANDLE errorPipeOrig = 0;
/* Handle to the event the parent uses to tell us to resume the child.
This is parsed off the command line. */
HANDLE resumeEvent = 0;
/* Handle to the event the parent uses to tell us to kill the child.
This is parsed off the command line. */
......@@ -75,7 +82,12 @@ int main()
/* Parse the error pipe handle. */
while(*cmdLine && *cmdLine == ' ') { ++cmdLine; }
sscanf(cmdLine, "%p", &errorPipe);
sscanf(cmdLine, "%p", &errorPipeOrig);
/* Parse the resume event handle. */
while(*cmdLine && *cmdLine != ' ') { ++cmdLine; }
while(*cmdLine && *cmdLine == ' ') { ++cmdLine; }
sscanf(cmdLine, "%p", &resumeEvent);
/* Parse the kill event handle. */
while(*cmdLine && *cmdLine != ' ') { ++cmdLine; }
......@@ -91,6 +103,22 @@ int main()
while(*cmdLine && *cmdLine != ' ') { ++cmdLine; }
while(*cmdLine && *cmdLine == ' ') { ++cmdLine; }
/* Create a non-inherited copy of the error pipe. We do not want
the child to get it. */
if(DuplicateHandle(GetCurrentProcess(), errorPipeOrig,
GetCurrentProcess(), &errorPipe,
0, FALSE, DUPLICATE_SAME_ACCESS))
{
/* Have a non-inherited duplicate. Close the inherited one. */
CloseHandle(errorPipeOrig);
}
else
{
/* Could not duplicate handle. Report the error. */
ReportLastError(errorPipeOrig);
return 1;
}
/* Create the subprocess. */
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
......@@ -100,32 +128,23 @@ int main()
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess(0, cmdLine, 0, 0, TRUE, 0, 0, 0, &si, &pi))
if(CreateProcess(0, cmdLine, 0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
/* Process created successfully. Close the error reporting pipe
to notify the parent of success. */
CloseHandle(errorPipe);
}
else
{
/* Error creating the process. Report the error to the parent
process through the special error reporting pipe. */
LPVOID lpMsgBuf;
DWORD n;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
WriteFile(errorPipe, lpMsgBuf, strlen(lpMsgBuf)+1, &n, 0);
LocalFree( lpMsgBuf );
ReportLastError(errorPipe);
return 1;
}
CloseHandle(pi.hThread);
/* Wait for subprocess to exit or for kill event from parent. */
/* Wait for resume or kill event from parent. */
waitHandles[0] = killEvent;
waitHandles[1] = pi.hProcess;
waitHandles[1] = resumeEvent;
waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE);
/* Check what happened. */
......@@ -135,22 +154,54 @@ int main()
TerminateProcess(pi.hProcess, 255);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 1;
}
else if(GetExitCodeProcess(pi.hProcess, &retVal))
else
{
/* We were asked to resume the child. */
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
}
/* Wait for subprocess to exit or for kill event from parent. */
waitHandles[0] = killEvent;
waitHandles[1] = pi.hProcess;
waitResult = WaitForMultipleObjects(2, waitHandles, 0, INFINITE);
/* Check what happened. */
if(waitResult == WAIT_OBJECT_0)
{
/* The child exited and we could get the return code. */
/* We were asked to kill the child. */
TerminateProcess(pi.hProcess, 255);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
return retVal;
return 1;
}
else
{
/* The child exited and we could not get the return code. Report
the problem to the parent process. */
DWORD n;
const char* msg = "Failed to get process return code.";
WriteFile(errorPipe, msg, strlen(msg)+1, &n, 0);
/* The child exited. Get the return code. */
GetExitCodeProcess(pi.hProcess, &retVal);
CloseHandle(pi.hProcess);
return -1;
return retVal;
}
}
void ReportLastError(HANDLE errorPipe)
{
LPVOID lpMsgBuf;
DWORD n;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
WriteFile(errorPipe, lpMsgBuf, strlen(lpMsgBuf)+1, &n, 0);
LocalFree( lpMsgBuf );
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment