|  | /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying | 
|  | file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */ | 
|  | #include "kwsysPrivate.h" | 
|  | #include KWSYS_HEADER(Process.h) | 
|  | #include KWSYS_HEADER(Encoding.h) | 
|  |  | 
|  | /* Work-around CMake dependency scanning limitation.  This must | 
|  | duplicate the above list of headers.  */ | 
|  | #if 0 | 
|  | #  include "Encoding.h.in" | 
|  | #  include "Process.h.in" | 
|  | #endif | 
|  |  | 
|  | /* | 
|  |  | 
|  | Implementation for Windows | 
|  |  | 
|  | On windows, a thread is created to wait for data on each pipe.  The | 
|  | threads are synchronized with the main thread to simulate the use of | 
|  | a UNIX-style select system call. | 
|  |  | 
|  | */ | 
|  |  | 
|  | #ifdef _MSC_VER | 
|  | #  pragma warning(push, 1) | 
|  | #endif | 
|  | #include <windows.h> /* Windows API */ | 
|  | #if defined(_MSC_VER) && _MSC_VER >= 1800 | 
|  | #  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx | 
|  | #endif | 
|  | #include <io.h>     /* _unlink */ | 
|  | #include <stdio.h>  /* snprintf */ | 
|  | #include <string.h> /* strlen, strdup */ | 
|  |  | 
|  | #ifndef _MAX_FNAME | 
|  | #  define _MAX_FNAME 4096 | 
|  | #endif | 
|  | #ifndef _MAX_PATH | 
|  | #  define _MAX_PATH 4096 | 
|  | #endif | 
|  |  | 
|  | #ifdef _MSC_VER | 
|  | #  pragma warning(pop) | 
|  | #  pragma warning(disable : 4514) | 
|  | #  pragma warning(disable : 4706) | 
|  | #endif | 
|  |  | 
|  | /* There are pipes for the process pipeline's stdout and stderr.  */ | 
|  | #define KWSYSPE_PIPE_COUNT 2 | 
|  | #define KWSYSPE_PIPE_STDOUT 0 | 
|  | #define KWSYSPE_PIPE_STDERR 1 | 
|  |  | 
|  | /* The maximum amount to read from a pipe at a time.  */ | 
|  | #define KWSYSPE_PIPE_BUFFER_SIZE 1024 | 
|  |  | 
|  | /* Debug output macro.  */ | 
|  | #if 0 | 
|  | #  define KWSYSPE_DEBUG(x)                                                    \ | 
|  | ((void*)cp == (void*)0x00226DE0                                           \ | 
|  | ? (fprintf(stderr, "%d/%p/%d ", (int)GetCurrentProcessId(), cp,        \ | 
|  | __LINE__),                                                  \ | 
|  | fprintf x, fflush(stderr), 1)                                       \ | 
|  | : (1)) | 
|  | #else | 
|  | #  define KWSYSPE_DEBUG(x) (void)1 | 
|  | #endif | 
|  |  | 
|  | typedef LARGE_INTEGER kwsysProcessTime; | 
|  |  | 
|  | typedef struct kwsysProcessCreateInformation_s | 
|  | { | 
|  | /* Windows child startup control data.  */ | 
|  | STARTUPINFOW StartupInfo; | 
|  |  | 
|  | /* Original handles before making inherited duplicates.  */ | 
|  | HANDLE hStdInput; | 
|  | HANDLE hStdOutput; | 
|  | HANDLE hStdError; | 
|  | } kwsysProcessCreateInformation; | 
|  |  | 
|  | typedef struct kwsysProcessPipeData_s kwsysProcessPipeData; | 
|  | static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd); | 
|  | static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, | 
|  | kwsysProcessPipeData* td); | 
|  | static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd); | 
|  | static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, | 
|  | kwsysProcessPipeData* td); | 
|  | static int kwsysProcessInitialize(kwsysProcess* cp); | 
|  | static DWORD kwsysProcessCreate(kwsysProcess* cp, int index, | 
|  | kwsysProcessCreateInformation* si); | 
|  | static void kwsysProcessDestroy(kwsysProcess* cp, int event); | 
|  | static DWORD kwsysProcessSetupOutputPipeFile(PHANDLE handle, char const* name); | 
|  | static void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle); | 
|  | static void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle); | 
|  | static void kwsysProcessCleanupHandle(PHANDLE h); | 
|  | static void kwsysProcessCleanup(kwsysProcess* cp, DWORD error); | 
|  | static void kwsysProcessCleanErrorMessage(kwsysProcess* cp); | 
|  | static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, | 
|  | kwsysProcessTime* timeoutTime); | 
|  | static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, | 
|  | double* userTimeout, | 
|  | kwsysProcessTime* timeoutLength); | 
|  | static kwsysProcessTime kwsysProcessTimeGetCurrent(void); | 
|  | static DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t); | 
|  | static double kwsysProcessTimeToDouble(kwsysProcessTime t); | 
|  | static kwsysProcessTime kwsysProcessTimeFromDouble(double d); | 
|  | static int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2); | 
|  | static kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, | 
|  | kwsysProcessTime in2); | 
|  | static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, | 
|  | kwsysProcessTime in2); | 
|  | static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, | 
|  | int idx); | 
|  | static void kwsysProcessKillTree(int pid); | 
|  | static void kwsysProcessDisablePipeThreads(kwsysProcess* cp); | 
|  | static int kwsysProcessesInitialize(void); | 
|  | static int kwsysTryEnterCreateProcessSection(void); | 
|  | static void kwsysLeaveCreateProcessSection(void); | 
|  | static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessId, | 
|  | int newProcessGroup); | 
|  | static void kwsysProcessesRemove(HANDLE hProcess); | 
|  | static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType); | 
|  |  | 
|  | /* A structure containing synchronization data for each thread.  */ | 
|  | typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync; | 
|  | struct kwsysProcessPipeSync_s | 
|  | { | 
|  | /* Handle to the thread.  */ | 
|  | HANDLE Thread; | 
|  |  | 
|  | /* Semaphore indicating to the thread that a process has started.  */ | 
|  | HANDLE Ready; | 
|  |  | 
|  | /* Semaphore indicating to the thread that it should begin work.  */ | 
|  | HANDLE Go; | 
|  |  | 
|  | /* Semaphore indicating thread has reset for another process.  */ | 
|  | HANDLE Reset; | 
|  | }; | 
|  |  | 
|  | /* A structure containing data for each pipe's threads.  */ | 
|  | struct kwsysProcessPipeData_s | 
|  | { | 
|  | /* ------------- Data managed per instance of kwsysProcess ------------- */ | 
|  |  | 
|  | /* Synchronization data for reading thread.  */ | 
|  | kwsysProcessPipeSync Reader; | 
|  |  | 
|  | /* Synchronization data for waking thread.  */ | 
|  | kwsysProcessPipeSync Waker; | 
|  |  | 
|  | /* Index of this pipe.  */ | 
|  | int Index; | 
|  |  | 
|  | /* The kwsysProcess instance owning this pipe.  */ | 
|  | kwsysProcess* Process; | 
|  |  | 
|  | /* ------------- Data managed per call to Execute ------------- */ | 
|  |  | 
|  | /* Buffer for data read in this pipe's thread.  */ | 
|  | char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE]; | 
|  |  | 
|  | /* The length of the data stored in the buffer.  */ | 
|  | DWORD DataLength; | 
|  |  | 
|  | /* Whether the pipe has been closed.  */ | 
|  | int Closed; | 
|  |  | 
|  | /* Handle for the read end of this pipe. */ | 
|  | HANDLE Read; | 
|  |  | 
|  | /* Handle for the write end of this pipe. */ | 
|  | HANDLE Write; | 
|  | }; | 
|  |  | 
|  | /* A structure containing results data for each process.  */ | 
|  | typedef struct kwsysProcessResults_s kwsysProcessResults; | 
|  | struct kwsysProcessResults_s | 
|  | { | 
|  | /* The status of the process.  */ | 
|  | int State; | 
|  |  | 
|  | /* The exceptional behavior that terminated the process, if any.  */ | 
|  | int ExitException; | 
|  |  | 
|  | /* The process exit code.  */ | 
|  | DWORD ExitCode; | 
|  |  | 
|  | /* The process return code, if any.  */ | 
|  | int ExitValue; | 
|  |  | 
|  | /* Description for the ExitException.  */ | 
|  | char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE + 1]; | 
|  | }; | 
|  |  | 
|  | /* Structure containing data used to implement the child's execution.  */ | 
|  | struct kwsysProcess_s | 
|  | { | 
|  | /* ------------- Data managed per instance of kwsysProcess ------------- */ | 
|  |  | 
|  | /* The status of the process structure.  */ | 
|  | int State; | 
|  |  | 
|  | /* The command lines to execute.  */ | 
|  | wchar_t** Commands; | 
|  | int NumberOfCommands; | 
|  |  | 
|  | /* The exit code of each command.  */ | 
|  | DWORD* CommandExitCodes; | 
|  |  | 
|  | /* The working directory for the child process.  */ | 
|  | wchar_t* WorkingDirectory; | 
|  |  | 
|  | /* Whether to create the child as a detached process.  */ | 
|  | int OptionDetach; | 
|  |  | 
|  | /* Whether the child was created as a detached process.  */ | 
|  | int Detached; | 
|  |  | 
|  | /* Whether to hide the child process's window.  */ | 
|  | int HideWindow; | 
|  |  | 
|  | /* Whether to treat command lines as verbatim.  */ | 
|  | int Verbatim; | 
|  |  | 
|  | /* Whether to merge stdout/stderr of the child.  */ | 
|  | int MergeOutput; | 
|  |  | 
|  | /* Whether to create the process in a new process group.  */ | 
|  | int CreateProcessGroup; | 
|  |  | 
|  | /* Mutex to protect the shared index used by threads to report data.  */ | 
|  | HANDLE SharedIndexMutex; | 
|  |  | 
|  | /* Semaphore used by threads to signal data ready.  */ | 
|  | HANDLE Full; | 
|  |  | 
|  | /* Whether we are currently deleting this kwsysProcess instance.  */ | 
|  | int Deleting; | 
|  |  | 
|  | /* Data specific to each pipe and its thread.  */ | 
|  | kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT]; | 
|  |  | 
|  | /* Name of files to which stdin and stdout pipes are attached.  */ | 
|  | char* PipeFileSTDIN; | 
|  | char* PipeFileSTDOUT; | 
|  | char* PipeFileSTDERR; | 
|  |  | 
|  | /* Whether each pipe is shared with the parent process.  */ | 
|  | int PipeSharedSTDIN; | 
|  | int PipeSharedSTDOUT; | 
|  | int PipeSharedSTDERR; | 
|  |  | 
|  | /* Native pipes provided by the user.  */ | 
|  | HANDLE PipeNativeSTDIN[2]; | 
|  | HANDLE PipeNativeSTDOUT[2]; | 
|  | HANDLE PipeNativeSTDERR[2]; | 
|  |  | 
|  | /* ------------- Data managed per call to Execute ------------- */ | 
|  |  | 
|  | /* Index of last pipe to report data, if any.  */ | 
|  | int CurrentIndex; | 
|  |  | 
|  | /* Index shared by threads to report data.  */ | 
|  | int SharedIndex; | 
|  |  | 
|  | /* The timeout length.  */ | 
|  | double Timeout; | 
|  |  | 
|  | /* Time at which the child started.  */ | 
|  | kwsysProcessTime StartTime; | 
|  |  | 
|  | /* Time at which the child will timeout.  Negative for no timeout.  */ | 
|  | kwsysProcessTime TimeoutTime; | 
|  |  | 
|  | /* Flag for whether the process was killed.  */ | 
|  | int Killed; | 
|  |  | 
|  | /* Flag for whether the timeout expired.  */ | 
|  | int TimeoutExpired; | 
|  |  | 
|  | /* Flag for whether the process has terminated.  */ | 
|  | int Terminated; | 
|  |  | 
|  | /* The number of pipes still open during execution and while waiting | 
|  | for pipes to close after process termination.  */ | 
|  | int PipesLeft; | 
|  |  | 
|  | /* Buffer for error messages.  */ | 
|  | char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE + 1]; | 
|  |  | 
|  | /* process results.  */ | 
|  | kwsysProcessResults* ProcessResults; | 
|  |  | 
|  | /* Windows process information data.  */ | 
|  | PROCESS_INFORMATION* ProcessInformation; | 
|  |  | 
|  | /* Data and process termination events for which to wait.  */ | 
|  | PHANDLE ProcessEvents; | 
|  | int ProcessEventsLength; | 
|  |  | 
|  | /* Real working directory of our own process.  */ | 
|  | DWORD RealWorkingDirectoryLength; | 
|  | wchar_t* RealWorkingDirectory; | 
|  |  | 
|  | /* Own handles for the child's ends of the pipes in the parent process. | 
|  | Used temporarily during process creation.  */ | 
|  | HANDLE PipeChildStd[3]; | 
|  | }; | 
|  |  | 
|  | kwsysProcess* kwsysProcess_New(void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Process control structure.  */ | 
|  | kwsysProcess* cp; | 
|  |  | 
|  | /* Windows version number data.  */ | 
|  | OSVERSIONINFO osv; | 
|  |  | 
|  | /* Initialize list of processes before we get any farther.  It's especially | 
|  | important that the console Ctrl handler be added BEFORE starting the | 
|  | first process.  This prevents the risk of an orphaned process being | 
|  | started by the main thread while the default Ctrl handler is in | 
|  | progress.  */ | 
|  | if (!kwsysProcessesInitialize()) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Allocate a process control structure.  */ | 
|  | cp = (kwsysProcess*)malloc(sizeof(kwsysProcess)); | 
|  | if (!cp) { | 
|  | /* Could not allocate memory for the control structure.  */ | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(cp, sizeof(*cp)); | 
|  |  | 
|  | /* Share stdin with the parent process by default.  */ | 
|  | cp->PipeSharedSTDIN = 1; | 
|  |  | 
|  | /* Set initial status.  */ | 
|  | cp->State = kwsysProcess_State_Starting; | 
|  |  | 
|  | /* Choose a method of running the child based on version of | 
|  | windows.  */ | 
|  | ZeroMemory(&osv, sizeof(osv)); | 
|  | osv.dwOSVersionInfoSize = sizeof(osv); | 
|  | #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx | 
|  | #  pragma warning(push) | 
|  | #  ifdef __INTEL_COMPILER | 
|  | #    pragma warning(disable : 1478) | 
|  | #  elif defined __clang__ | 
|  | #    pragma clang diagnostic push | 
|  | #    pragma clang diagnostic ignored "-Wdeprecated-declarations" | 
|  | #  else | 
|  | #    pragma warning(disable : 4996) | 
|  | #  endif | 
|  | #endif | 
|  | GetVersionEx(&osv); | 
|  | #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx | 
|  | #  ifdef __clang__ | 
|  | #    pragma clang diagnostic pop | 
|  | #  else | 
|  | #    pragma warning(pop) | 
|  | #  endif | 
|  | #endif | 
|  | if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { | 
|  | /* Win9x no longer supported.  */ | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Initially no thread owns the mutex.  Initialize semaphore to 1.  */ | 
|  | if (!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Initially no data are available.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Full = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Create the thread to read each pipe.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | DWORD dummy = 0; | 
|  |  | 
|  | /* Assign the thread its index.  */ | 
|  | cp->Pipe[i].Index = i; | 
|  |  | 
|  | /* Give the thread a pointer back to the kwsysProcess instance.  */ | 
|  | cp->Pipe[i].Process = cp; | 
|  |  | 
|  | /* No process is yet running.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* The pipe is not yet reset.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* The thread's buffer is initially empty.  Initialize semaphore to 1.  */ | 
|  | if (!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Create the reading thread.  It will block immediately.  The | 
|  | thread will not make deeply nested calls, so we need only a | 
|  | small stack.  */ | 
|  | if (!(cp->Pipe[i].Reader.Thread = CreateThread( | 
|  | 0, 1024, kwsysProcessPipeThreadRead, &cp->Pipe[i], 0, &dummy))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* No process is yet running.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* The pipe is not yet reset.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* The waker should not wake immediately.  Initialize semaphore to 0.  */ | 
|  | if (!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Create the waking thread.  It will block immediately.  The | 
|  | thread will not make deeply nested calls, so we need only a | 
|  | small stack.  */ | 
|  | if (!(cp->Pipe[i].Waker.Thread = CreateThread( | 
|  | 0, 1024, kwsysProcessPipeThreadWake, &cp->Pipe[i], 0, &dummy))) { | 
|  | kwsysProcess_Delete(cp); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | for (i = 0; i < 3; ++i) { | 
|  | cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | return cp; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_Delete(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Make sure we have an instance.  */ | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* If the process is executing, wait for it to finish.  */ | 
|  | if (cp->State == kwsysProcess_State_Executing) { | 
|  | if (cp->Detached) { | 
|  | kwsysProcess_Disown(cp); | 
|  | } else { | 
|  | kwsysProcess_WaitForExit(cp, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* We are deleting the kwsysProcess instance.  */ | 
|  | cp->Deleting = 1; | 
|  |  | 
|  | /* Terminate each of the threads.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | /* Terminate this reading thread.  */ | 
|  | if (cp->Pipe[i].Reader.Thread) { | 
|  | /* Signal the thread we are ready for it.  It will terminate | 
|  | immediately since Deleting is set.  */ | 
|  | ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); | 
|  |  | 
|  | /* Wait for the thread to exit.  */ | 
|  | WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE); | 
|  |  | 
|  | /* Close the handle to the thread. */ | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread); | 
|  | } | 
|  |  | 
|  | /* Terminate this waking thread.  */ | 
|  | if (cp->Pipe[i].Waker.Thread) { | 
|  | /* Signal the thread we are ready for it.  It will terminate | 
|  | immediately since Deleting is set.  */ | 
|  | ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); | 
|  |  | 
|  | /* Wait for the thread to exit.  */ | 
|  | WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE); | 
|  |  | 
|  | /* Close the handle to the thread. */ | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread); | 
|  | } | 
|  |  | 
|  | /* Cleanup the pipe's semaphores.  */ | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Ready); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Go); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Reset); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Ready); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Go); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Reset); | 
|  | } | 
|  |  | 
|  | /* Close the shared semaphores.  */ | 
|  | kwsysProcessCleanupHandle(&cp->SharedIndexMutex); | 
|  | kwsysProcessCleanupHandle(&cp->Full); | 
|  |  | 
|  | /* Free memory.  */ | 
|  | kwsysProcess_SetCommand(cp, 0); | 
|  | kwsysProcess_SetWorkingDirectory(cp, 0); | 
|  | kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0); | 
|  | kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0); | 
|  | kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0); | 
|  | free(cp->CommandExitCodes); | 
|  | free(cp->ProcessResults); | 
|  | free(cp); | 
|  | } | 
|  |  | 
|  | int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command) | 
|  | { | 
|  | int i; | 
|  | if (!cp) { | 
|  | return 0; | 
|  | } | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | free(cp->Commands[i]); | 
|  | } | 
|  | cp->NumberOfCommands = 0; | 
|  | if (cp->Commands) { | 
|  | free(cp->Commands); | 
|  | cp->Commands = 0; | 
|  | } | 
|  | if (command) { | 
|  | return kwsysProcess_AddCommand(cp, command); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command) | 
|  | { | 
|  | int newNumberOfCommands; | 
|  | wchar_t** newCommands; | 
|  |  | 
|  | /* Make sure we have a command to add.  */ | 
|  | if (!cp || !command || !*command) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Allocate a new array for command pointers.  */ | 
|  | newNumberOfCommands = cp->NumberOfCommands + 1; | 
|  | if (!(newCommands = | 
|  | (wchar_t**)malloc(sizeof(wchar_t*) * newNumberOfCommands))) { | 
|  | /* Out of memory.  */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Copy any existing commands into the new array.  */ | 
|  | { | 
|  | int i; | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | newCommands[i] = cp->Commands[i]; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (cp->Verbatim) { | 
|  | /* Copy the verbatim command line into the buffer.  */ | 
|  | newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(*command); | 
|  | } else { | 
|  | /* Encode the arguments so CommandLineToArgvW can decode | 
|  | them from the command line string in the child.  */ | 
|  | char buffer[32768]; /* CreateProcess max command-line length.  */ | 
|  | char* end = buffer + sizeof(buffer); | 
|  | char* out = buffer; | 
|  | char const* const* a; | 
|  | for (a = command; *a; ++a) { | 
|  | int quote = !**a; /* Quote the empty string.  */ | 
|  | int slashes = 0; | 
|  | char const* c; | 
|  | if (a != command && out != end) { | 
|  | *out++ = ' '; | 
|  | } | 
|  | for (c = *a; !quote && *c; ++c) { | 
|  | quote = (*c == ' ' || *c == '\t'); | 
|  | } | 
|  | if (quote && out != end) { | 
|  | *out++ = '"'; | 
|  | } | 
|  | for (c = *a; *c; ++c) { | 
|  | if (*c == '\\') { | 
|  | ++slashes; | 
|  | } else { | 
|  | if (*c == '"') { | 
|  | // Add n+1 backslashes to total 2n+1 before internal '"'. | 
|  | while (slashes-- >= 0 && out != end) { | 
|  | *out++ = '\\'; | 
|  | } | 
|  | } | 
|  | slashes = 0; | 
|  | } | 
|  | if (out != end) { | 
|  | *out++ = *c; | 
|  | } | 
|  | } | 
|  | if (quote) { | 
|  | // Add n backslashes to total 2n before ending '"'. | 
|  | while (slashes-- > 0 && out != end) { | 
|  | *out++ = '\\'; | 
|  | } | 
|  | if (out != end) { | 
|  | *out++ = '"'; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (out != end) { | 
|  | *out = '\0'; | 
|  | newCommands[cp->NumberOfCommands] = kwsysEncoding_DupToWide(buffer); | 
|  | } else { | 
|  | newCommands[cp->NumberOfCommands] = 0; | 
|  | } | 
|  | } | 
|  | if (!newCommands[cp->NumberOfCommands]) { | 
|  | /* Out of memory or command line too long.  */ | 
|  | free(newCommands); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Save the new array of commands.  */ | 
|  | free(cp->Commands); | 
|  | cp->Commands = newCommands; | 
|  | cp->NumberOfCommands = newNumberOfCommands; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout) | 
|  | { | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  | cp->Timeout = timeout; | 
|  | if (cp->Timeout < 0) { | 
|  | cp->Timeout = 0; | 
|  | } | 
|  | // Force recomputation of TimeoutTime. | 
|  | cp->TimeoutTime.QuadPart = -1; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, char const* dir) | 
|  | { | 
|  | if (!cp) { | 
|  | return 0; | 
|  | } | 
|  | if (cp->WorkingDirectory) { | 
|  | free(cp->WorkingDirectory); | 
|  | cp->WorkingDirectory = 0; | 
|  | } | 
|  | if (dir && dir[0]) { | 
|  | wchar_t* wdir = kwsysEncoding_DupToWide(dir); | 
|  | /* We must convert the working directory to a full path.  */ | 
|  | DWORD length = GetFullPathNameW(wdir, 0, NULL, NULL); | 
|  | if (length > 0) { | 
|  | wchar_t* work_dir = malloc(length * sizeof(wchar_t)); | 
|  | if (!work_dir) { | 
|  | free(wdir); | 
|  | return 0; | 
|  | } | 
|  | if (!GetFullPathNameW(wdir, length, work_dir, NULL)) { | 
|  | free(work_dir); | 
|  | free(wdir); | 
|  | return 0; | 
|  | } | 
|  | cp->WorkingDirectory = work_dir; | 
|  | } | 
|  | free(wdir); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, char const* file) | 
|  | { | 
|  | char** pfile; | 
|  | if (!cp) { | 
|  | return 0; | 
|  | } | 
|  | switch (pipe) { | 
|  | case kwsysProcess_Pipe_STDIN: | 
|  | pfile = &cp->PipeFileSTDIN; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDOUT: | 
|  | pfile = &cp->PipeFileSTDOUT; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDERR: | 
|  | pfile = &cp->PipeFileSTDERR; | 
|  | break; | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | if (*pfile) { | 
|  | free(*pfile); | 
|  | *pfile = 0; | 
|  | } | 
|  | if (file) { | 
|  | *pfile = strdup(file); | 
|  | if (!*pfile) { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* If we are redirecting the pipe, do not share it or use a native | 
|  | pipe.  */ | 
|  | if (*pfile) { | 
|  | kwsysProcess_SetPipeNative(cp, pipe, 0); | 
|  | kwsysProcess_SetPipeShared(cp, pipe, 0); | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) | 
|  | { | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (pipe) { | 
|  | case kwsysProcess_Pipe_STDIN: | 
|  | cp->PipeSharedSTDIN = shared ? 1 : 0; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDOUT: | 
|  | cp->PipeSharedSTDOUT = shared ? 1 : 0; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDERR: | 
|  | cp->PipeSharedSTDERR = shared ? 1 : 0; | 
|  | break; | 
|  | default: | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* If we are sharing the pipe, do not redirect it to a file or use a | 
|  | native pipe.  */ | 
|  | if (shared) { | 
|  | kwsysProcess_SetPipeFile(cp, pipe, 0); | 
|  | kwsysProcess_SetPipeNative(cp, pipe, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void kwsysProcess_SetPipeNative(kwsysProcess* cp, int pipe, const HANDLE p[2]) | 
|  | { | 
|  | HANDLE* pPipeNative = 0; | 
|  |  | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (pipe) { | 
|  | case kwsysProcess_Pipe_STDIN: | 
|  | pPipeNative = cp->PipeNativeSTDIN; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDOUT: | 
|  | pPipeNative = cp->PipeNativeSTDOUT; | 
|  | break; | 
|  | case kwsysProcess_Pipe_STDERR: | 
|  | pPipeNative = cp->PipeNativeSTDERR; | 
|  | break; | 
|  | default: | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Copy the native pipe handles provided.  */ | 
|  | if (p) { | 
|  | pPipeNative[0] = p[0]; | 
|  | pPipeNative[1] = p[1]; | 
|  | } else { | 
|  | pPipeNative[0] = 0; | 
|  | pPipeNative[1] = 0; | 
|  | } | 
|  |  | 
|  | /* If we are using a native pipe, do not share it or redirect it to | 
|  | a file.  */ | 
|  | if (p) { | 
|  | kwsysProcess_SetPipeFile(cp, pipe, 0); | 
|  | kwsysProcess_SetPipeShared(cp, pipe, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) | 
|  | { | 
|  | if (!cp) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | switch (optionId) { | 
|  | case kwsysProcess_Option_Detach: | 
|  | return cp->OptionDetach; | 
|  | case kwsysProcess_Option_HideWindow: | 
|  | return cp->HideWindow; | 
|  | case kwsysProcess_Option_MergeOutput: | 
|  | return cp->MergeOutput; | 
|  | case kwsysProcess_Option_Verbatim: | 
|  | return cp->Verbatim; | 
|  | case kwsysProcess_Option_CreateProcessGroup: | 
|  | return cp->CreateProcessGroup; | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value) | 
|  | { | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (optionId) { | 
|  | case kwsysProcess_Option_Detach: | 
|  | cp->OptionDetach = value; | 
|  | break; | 
|  | case kwsysProcess_Option_HideWindow: | 
|  | cp->HideWindow = value; | 
|  | break; | 
|  | case kwsysProcess_Option_MergeOutput: | 
|  | cp->MergeOutput = value; | 
|  | break; | 
|  | case kwsysProcess_Option_Verbatim: | 
|  | cp->Verbatim = value; | 
|  | break; | 
|  | case kwsysProcess_Option_CreateProcessGroup: | 
|  | cp->CreateProcessGroup = value; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetState(kwsysProcess* cp) | 
|  | { | 
|  | return cp ? cp->State : kwsysProcess_State_Error; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitException(kwsysProcess* cp) | 
|  | { | 
|  | return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) | 
|  | ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitException | 
|  | : kwsysProcess_Exception_Other; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitValue(kwsysProcess* cp) | 
|  | { | 
|  | return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) | 
|  | ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitValue | 
|  | : -1; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitCode(kwsysProcess* cp) | 
|  | { | 
|  | return (cp && cp->ProcessResults && (cp->NumberOfCommands > 0)) | 
|  | ? cp->ProcessResults[cp->NumberOfCommands - 1].ExitCode | 
|  | : 0; | 
|  | } | 
|  |  | 
|  | char const* kwsysProcess_GetErrorString(kwsysProcess* cp) | 
|  | { | 
|  | if (!cp) { | 
|  | return "Process management structure could not be allocated"; | 
|  | } else if (cp->State == kwsysProcess_State_Error) { | 
|  | return cp->ErrorMessage; | 
|  | } | 
|  | return "Success"; | 
|  | } | 
|  |  | 
|  | char const* kwsysProcess_GetExceptionString(kwsysProcess* cp) | 
|  | { | 
|  | if (!(cp && cp->ProcessResults && (cp->NumberOfCommands > 0))) { | 
|  | return "GetExceptionString called with NULL process management structure"; | 
|  | } else if (cp->State == kwsysProcess_State_Exception) { | 
|  | return cp->ProcessResults[cp->NumberOfCommands - 1].ExitExceptionString; | 
|  | } | 
|  | return "No exception"; | 
|  | } | 
|  |  | 
|  | /* the index should be in array bound. */ | 
|  | #define KWSYSPE_IDX_CHK(RET)                                                  \ | 
|  | if (!cp || idx >= cp->NumberOfCommands || idx < 0) {                        \ | 
|  | KWSYSPE_DEBUG((stderr, "array index out of bound\n"));                    \ | 
|  | return RET;                                                               \ | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetStateByIndex(kwsysProcess* cp, int idx) | 
|  | { | 
|  | KWSYSPE_IDX_CHK(kwsysProcess_State_Error) | 
|  | return cp->ProcessResults[idx].State; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitExceptionByIndex(kwsysProcess* cp, int idx) | 
|  | { | 
|  | KWSYSPE_IDX_CHK(kwsysProcess_Exception_Other) | 
|  | return cp->ProcessResults[idx].ExitException; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitValueByIndex(kwsysProcess* cp, int idx) | 
|  | { | 
|  | KWSYSPE_IDX_CHK(-1) | 
|  | return cp->ProcessResults[idx].ExitValue; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_GetExitCodeByIndex(kwsysProcess* cp, int idx) | 
|  | { | 
|  | KWSYSPE_IDX_CHK(-1) | 
|  | return cp->CommandExitCodes[idx]; | 
|  | } | 
|  |  | 
|  | char const* kwsysProcess_GetExceptionStringByIndex(kwsysProcess* cp, int idx) | 
|  | { | 
|  | KWSYSPE_IDX_CHK("GetExceptionString called with NULL process management " | 
|  | "structure or index out of bound") | 
|  | if (cp->ProcessResults[idx].State == kwsysProcess_StateByIndex_Exception) { | 
|  | return cp->ProcessResults[idx].ExitExceptionString; | 
|  | } | 
|  | return "No exception"; | 
|  | } | 
|  |  | 
|  | #undef KWSYSPE_IDX_CHK | 
|  |  | 
|  | void kwsysProcess_Execute(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Do not execute a second time.  */ | 
|  | if (!cp || cp->State == kwsysProcess_State_Executing) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Make sure we have something to run.  */ | 
|  | if (cp->NumberOfCommands < 1) { | 
|  | strcpy(cp->ErrorMessage, "No command"); | 
|  | cp->State = kwsysProcess_State_Error; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Initialize the control structure for a new process.  */ | 
|  | if (!kwsysProcessInitialize(cp)) { | 
|  | strcpy(cp->ErrorMessage, "Out of memory"); | 
|  | cp->State = kwsysProcess_State_Error; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Save the real working directory of this process and change to | 
|  | the working directory for the child processes.  This is needed | 
|  | to make pipe file paths evaluate correctly.  */ | 
|  | if (cp->WorkingDirectory) { | 
|  | if (!GetCurrentDirectoryW(cp->RealWorkingDirectoryLength, | 
|  | cp->RealWorkingDirectory)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  | if (!SetCurrentDirectoryW(cp->WorkingDirectory)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Setup the stdin pipe for the first process.  */ | 
|  | if (cp->PipeFileSTDIN) { | 
|  | /* Create a handle to read a file for stdin.  */ | 
|  | wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); | 
|  | DWORD error; | 
|  | cp->PipeChildStd[0] = | 
|  | CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, | 
|  | OPEN_EXISTING, 0, 0); | 
|  | error = GetLastError(); /* Check now in case free changes this.  */ | 
|  | free(wstdin); | 
|  | if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { | 
|  | kwsysProcessCleanup(cp, error); | 
|  | return; | 
|  | } | 
|  | } else if (cp->PipeSharedSTDIN) { | 
|  | /* Share this process's stdin with the child.  */ | 
|  | kwsysProcessSetupSharedPipe(STD_INPUT_HANDLE, &cp->PipeChildStd[0]); | 
|  | } else if (cp->PipeNativeSTDIN[0]) { | 
|  | /* Use the provided native pipe.  */ | 
|  | kwsysProcessSetupPipeNative(cp->PipeNativeSTDIN[0], &cp->PipeChildStd[0]); | 
|  | } else { | 
|  | /* Explicitly give the child no stdin.  */ | 
|  | cp->PipeChildStd[0] = INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | /* Create the output pipe for the last process. | 
|  | We always create this so the pipe thread can run even if we | 
|  | do not end up giving the write end to the child below.  */ | 
|  | if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDOUT].Read, | 
|  | &cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, 0, 0)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cp->PipeFileSTDOUT) { | 
|  | /* Use a file for stdout.  */ | 
|  | DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[1], | 
|  | cp->PipeFileSTDOUT); | 
|  | if (error) { | 
|  | kwsysProcessCleanup(cp, error); | 
|  | return; | 
|  | } | 
|  | } else if (cp->PipeSharedSTDOUT) { | 
|  | /* Use the parent stdout.  */ | 
|  | kwsysProcessSetupSharedPipe(STD_OUTPUT_HANDLE, &cp->PipeChildStd[1]); | 
|  | } else if (cp->PipeNativeSTDOUT[1]) { | 
|  | /* Use the given handle for stdout.  */ | 
|  | kwsysProcessSetupPipeNative(cp->PipeNativeSTDOUT[1], &cp->PipeChildStd[1]); | 
|  | } else { | 
|  | /* Use our pipe for stdout.  Duplicate the handle since our waker | 
|  | thread will use the original.  Do not make it inherited yet.  */ | 
|  | if (!DuplicateHandle(GetCurrentProcess(), | 
|  | cp->Pipe[KWSYSPE_PIPE_STDOUT].Write, | 
|  | GetCurrentProcess(), &cp->PipeChildStd[1], 0, FALSE, | 
|  | DUPLICATE_SAME_ACCESS)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Create stderr pipe to be shared by all processes in the pipeline. | 
|  | We always create this so the pipe thread can run even if we do not | 
|  | end up giving the write end to the child below.  */ | 
|  | if (!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read, | 
|  | &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (cp->PipeFileSTDERR) { | 
|  | /* Use a file for stderr.  */ | 
|  | DWORD error = kwsysProcessSetupOutputPipeFile(&cp->PipeChildStd[2], | 
|  | cp->PipeFileSTDERR); | 
|  | if (error) { | 
|  | kwsysProcessCleanup(cp, error); | 
|  | return; | 
|  | } | 
|  | } else if (cp->PipeSharedSTDERR) { | 
|  | /* Use the parent stderr.  */ | 
|  | kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE, &cp->PipeChildStd[2]); | 
|  | } else if (cp->PipeNativeSTDERR[1]) { | 
|  | /* Use the given handle for stderr.  */ | 
|  | kwsysProcessSetupPipeNative(cp->PipeNativeSTDERR[1], &cp->PipeChildStd[2]); | 
|  | } else { | 
|  | /* Use our pipe for stderr.  Duplicate the handle since our waker | 
|  | thread will use the original.  Do not make it inherited yet.  */ | 
|  | if (!DuplicateHandle(GetCurrentProcess(), | 
|  | cp->Pipe[KWSYSPE_PIPE_STDERR].Write, | 
|  | GetCurrentProcess(), &cp->PipeChildStd[2], 0, FALSE, | 
|  | DUPLICATE_SAME_ACCESS)) { | 
|  | kwsysProcessCleanup(cp, GetLastError()); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Create the pipeline of processes.  */ | 
|  | { | 
|  | /* Child startup control data.  */ | 
|  | kwsysProcessCreateInformation si; | 
|  | HANDLE nextStdInput = cp->PipeChildStd[0]; | 
|  |  | 
|  | /* Initialize startup info data.  */ | 
|  | ZeroMemory(&si, sizeof(si)); | 
|  | si.StartupInfo.cb = sizeof(si.StartupInfo); | 
|  |  | 
|  | /* Decide whether a child window should be shown.  */ | 
|  | si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; | 
|  | si.StartupInfo.wShowWindow = | 
|  | (unsigned short)(cp->HideWindow ? SW_HIDE : SW_SHOWDEFAULT); | 
|  |  | 
|  | /* Connect the child's output pipes to the threads.  */ | 
|  | si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; | 
|  |  | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | /* Setup the process's pipes.  */ | 
|  | si.hStdInput = nextStdInput; | 
|  | if (i == cp->NumberOfCommands - 1) { | 
|  | /* The last child gets the overall stdout.  */ | 
|  | nextStdInput = INVALID_HANDLE_VALUE; | 
|  | si.hStdOutput = cp->PipeChildStd[1]; | 
|  | } else { | 
|  | /* Create a pipe to sit between the children.  */ | 
|  | HANDLE p[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE }; | 
|  | if (!CreatePipe(&p[0], &p[1], 0, 0)) { | 
|  | DWORD error = GetLastError(); | 
|  | if (nextStdInput != cp->PipeChildStd[0]) { | 
|  | kwsysProcessCleanupHandle(&nextStdInput); | 
|  | } | 
|  | kwsysProcessCleanup(cp, error); | 
|  | return; | 
|  | } | 
|  | nextStdInput = p[0]; | 
|  | si.hStdOutput = p[1]; | 
|  | } | 
|  | si.hStdError = | 
|  | cp->MergeOutput ? cp->PipeChildStd[1] : cp->PipeChildStd[2]; | 
|  |  | 
|  | { | 
|  | DWORD error = kwsysProcessCreate(cp, i, &si); | 
|  |  | 
|  | /* Close our copies of pipes used between children.  */ | 
|  | if (si.hStdInput != cp->PipeChildStd[0]) { | 
|  | kwsysProcessCleanupHandle(&si.hStdInput); | 
|  | } | 
|  | if (si.hStdOutput != cp->PipeChildStd[1]) { | 
|  | kwsysProcessCleanupHandle(&si.hStdOutput); | 
|  | } | 
|  | if (si.hStdError != cp->PipeChildStd[2] && !cp->MergeOutput) { | 
|  | kwsysProcessCleanupHandle(&si.hStdError); | 
|  | } | 
|  | if (!error) { | 
|  | cp->ProcessEvents[i + 1] = cp->ProcessInformation[i].hProcess; | 
|  | } else { | 
|  | if (nextStdInput != cp->PipeChildStd[0]) { | 
|  | kwsysProcessCleanupHandle(&nextStdInput); | 
|  | } | 
|  | kwsysProcessCleanup(cp, error); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* The parent process does not need the child's pipe ends.  */ | 
|  | for (i = 0; i < 3; ++i) { | 
|  | kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); | 
|  | } | 
|  |  | 
|  | /* Restore the working directory.  */ | 
|  | if (cp->RealWorkingDirectory) { | 
|  | SetCurrentDirectoryW(cp->RealWorkingDirectory); | 
|  | free(cp->RealWorkingDirectory); | 
|  | cp->RealWorkingDirectory = 0; | 
|  | } | 
|  |  | 
|  | /* The timeout period starts now.  */ | 
|  | cp->StartTime = kwsysProcessTimeGetCurrent(); | 
|  | cp->TimeoutTime = kwsysProcessTimeFromDouble(-1); | 
|  |  | 
|  | /* All processes in the pipeline have been started in suspended | 
|  | mode.  Resume them all now.  */ | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | ResumeThread(cp->ProcessInformation[i].hThread); | 
|  | } | 
|  |  | 
|  | /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */ | 
|  | /* Tell the pipe threads that a process has started.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0); | 
|  | ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0); | 
|  | } | 
|  |  | 
|  | /* We don't care about the children's main threads.  */ | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); | 
|  | } | 
|  |  | 
|  | /* No pipe has reported data.  */ | 
|  | cp->CurrentIndex = KWSYSPE_PIPE_COUNT; | 
|  | cp->PipesLeft = KWSYSPE_PIPE_COUNT; | 
|  |  | 
|  | /* The process has now started.  */ | 
|  | cp->State = kwsysProcess_State_Executing; | 
|  | cp->Detached = cp->OptionDetach; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_Disown(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* Make sure we are executing a detached process.  */ | 
|  | if (!cp || !cp->Detached || cp->State != kwsysProcess_State_Executing || | 
|  | cp->TimeoutExpired || cp->Killed || cp->Terminated) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Disable the reading threads.  */ | 
|  | kwsysProcessDisablePipeThreads(cp); | 
|  |  | 
|  | /* Wait for all pipe threads to reset.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); | 
|  | WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); | 
|  | } | 
|  |  | 
|  | /* We will not wait for exit, so cleanup now.  */ | 
|  | kwsysProcessCleanup(cp, 0); | 
|  |  | 
|  | /* The process has been disowned.  */ | 
|  | cp->State = kwsysProcess_State_Disowned; | 
|  | } | 
|  |  | 
|  | int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length, | 
|  | double* userTimeout) | 
|  | { | 
|  | kwsysProcessTime userStartTime; | 
|  | kwsysProcessTime timeoutLength; | 
|  | kwsysProcessTime timeoutTime; | 
|  | DWORD timeout; | 
|  | int user; | 
|  | int done = 0; | 
|  | int expired = 0; | 
|  | int pipeId = kwsysProcess_Pipe_None; | 
|  | DWORD w; | 
|  |  | 
|  | /* Make sure we are executing a process.  */ | 
|  | if (!cp || cp->State != kwsysProcess_State_Executing || cp->Killed || | 
|  | cp->TimeoutExpired) { | 
|  | return kwsysProcess_Pipe_None; | 
|  | } | 
|  |  | 
|  | /* Record the time at which user timeout period starts.  */ | 
|  | userStartTime = kwsysProcessTimeGetCurrent(); | 
|  |  | 
|  | /* Calculate the time at which a timeout will expire, and whether it | 
|  | is the user or process timeout.  */ | 
|  | user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime); | 
|  |  | 
|  | /* Loop until we have a reason to return.  */ | 
|  | while (!done && cp->PipesLeft > 0) { | 
|  | /* If we previously got data from a thread, let it know we are | 
|  | done with the data.  */ | 
|  | if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { | 
|  | KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); | 
|  | ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); | 
|  | cp->CurrentIndex = KWSYSPE_PIPE_COUNT; | 
|  | } | 
|  |  | 
|  | /* Setup a timeout if required.  */ | 
|  | if (kwsysProcessGetTimeoutLeft(&timeoutTime, user ? userTimeout : 0, | 
|  | &timeoutLength)) { | 
|  | /* Timeout has already expired.  */ | 
|  | expired = 1; | 
|  | break; | 
|  | } | 
|  | if (timeoutTime.QuadPart < 0) { | 
|  | timeout = INFINITE; | 
|  | } else { | 
|  | timeout = kwsysProcessTimeToDWORD(timeoutLength); | 
|  | } | 
|  |  | 
|  | /* Wait for a pipe's thread to signal or a process to terminate.  */ | 
|  | w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents, 0, | 
|  | timeout); | 
|  | if (w == WAIT_TIMEOUT) { | 
|  | /* Timeout has expired.  */ | 
|  | expired = 1; | 
|  | done = 1; | 
|  | } else if (w == WAIT_OBJECT_0) { | 
|  | /* Save the index of the reporting thread and release the mutex. | 
|  | The thread will block until we signal its Empty mutex.  */ | 
|  | cp->CurrentIndex = cp->SharedIndex; | 
|  | ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); | 
|  |  | 
|  | /* Data are available or a pipe closed.  */ | 
|  | if (cp->Pipe[cp->CurrentIndex].Closed) { | 
|  | /* The pipe closed at the write end.  Close the read end and | 
|  | inform the wakeup thread it is done with this process.  */ | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); | 
|  | ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Waker.Go, 1, 0); | 
|  | KWSYSPE_DEBUG((stderr, "wakeup %d\n", cp->CurrentIndex)); | 
|  | --cp->PipesLeft; | 
|  | } else if (data && length) { | 
|  | /* Report this data.  */ | 
|  | *data = cp->Pipe[cp->CurrentIndex].DataBuffer; | 
|  | *length = cp->Pipe[cp->CurrentIndex].DataLength; | 
|  | switch (cp->CurrentIndex) { | 
|  | case KWSYSPE_PIPE_STDOUT: | 
|  | pipeId = kwsysProcess_Pipe_STDOUT; | 
|  | break; | 
|  | case KWSYSPE_PIPE_STDERR: | 
|  | pipeId = kwsysProcess_Pipe_STDERR; | 
|  | break; | 
|  | } | 
|  | done = 1; | 
|  | } | 
|  | } else { | 
|  | /* A process has terminated.  */ | 
|  | kwsysProcessDestroy(cp, w - WAIT_OBJECT_0); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Update the user timeout.  */ | 
|  | if (userTimeout) { | 
|  | kwsysProcessTime userEndTime = kwsysProcessTimeGetCurrent(); | 
|  | kwsysProcessTime difference = | 
|  | kwsysProcessTimeSubtract(userEndTime, userStartTime); | 
|  | double d = kwsysProcessTimeToDouble(difference); | 
|  | *userTimeout -= d; | 
|  | if (*userTimeout < 0) { | 
|  | *userTimeout = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Check what happened.  */ | 
|  | if (pipeId) { | 
|  | /* Data are ready on a pipe.  */ | 
|  | return pipeId; | 
|  | } else if (expired) { | 
|  | /* A timeout has expired.  */ | 
|  | if (user) { | 
|  | /* The user timeout has expired.  It has no time left.  */ | 
|  | return kwsysProcess_Pipe_Timeout; | 
|  | } else { | 
|  | /* The process timeout has expired.  Kill the child now.  */ | 
|  | KWSYSPE_DEBUG((stderr, "killing child because timeout expired\n")); | 
|  | kwsysProcess_Kill(cp); | 
|  | cp->TimeoutExpired = 1; | 
|  | cp->Killed = 0; | 
|  | return kwsysProcess_Pipe_None; | 
|  | } | 
|  | } else { | 
|  | /* The children have terminated and no more data are available.  */ | 
|  | return kwsysProcess_Pipe_None; | 
|  | } | 
|  | } | 
|  |  | 
|  | int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout) | 
|  | { | 
|  | int i; | 
|  | int pipe; | 
|  |  | 
|  | /* Make sure we are executing a process.  */ | 
|  | if (!cp || cp->State != kwsysProcess_State_Executing) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Wait for the process to terminate.  Ignore all data.  */ | 
|  | while ((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0) { | 
|  | if (pipe == kwsysProcess_Pipe_Timeout) { | 
|  | /* The user timeout has expired.  */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | KWSYSPE_DEBUG((stderr, "no more data\n")); | 
|  |  | 
|  | /* When the last pipe closes in WaitForData, the loop terminates | 
|  | without releasing the pipe's thread.  Release it now.  */ | 
|  | if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { | 
|  | KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); | 
|  | ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); | 
|  | cp->CurrentIndex = KWSYSPE_PIPE_COUNT; | 
|  | } | 
|  |  | 
|  | /* Wait for all pipe threads to reset.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | KWSYSPE_DEBUG((stderr, "waiting reader reset %d\n", i)); | 
|  | WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE); | 
|  | KWSYSPE_DEBUG((stderr, "waiting waker reset %d\n", i)); | 
|  | WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE); | 
|  | } | 
|  |  | 
|  | /* ---- It is now safe again to call kwsysProcessCleanup. ----- */ | 
|  | /* Close all the pipes.  */ | 
|  | kwsysProcessCleanup(cp, 0); | 
|  |  | 
|  | /* Determine the outcome.  */ | 
|  | if (cp->Killed) { | 
|  | /* We killed the child.  */ | 
|  | cp->State = kwsysProcess_State_Killed; | 
|  | } else if (cp->TimeoutExpired) { | 
|  | /* The timeout expired.  */ | 
|  | cp->State = kwsysProcess_State_Expired; | 
|  | } else { | 
|  | /* The children exited.  Report the outcome of the child processes.  */ | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | cp->ProcessResults[i].ExitCode = cp->CommandExitCodes[i]; | 
|  | if ((cp->ProcessResults[i].ExitCode & 0xF0000000) == 0xC0000000) { | 
|  | /* Child terminated due to exceptional behavior.  */ | 
|  | cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exception; | 
|  | cp->ProcessResults[i].ExitValue = 1; | 
|  | kwsysProcessSetExitExceptionByIndex(cp, cp->ProcessResults[i].ExitCode, | 
|  | i); | 
|  | } else { | 
|  | /* Child exited without exception.  */ | 
|  | cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Exited; | 
|  | cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; | 
|  | cp->ProcessResults[i].ExitValue = cp->ProcessResults[i].ExitCode; | 
|  | } | 
|  | } | 
|  | /* support legacy state status value */ | 
|  | cp->State = cp->ProcessResults[cp->NumberOfCommands - 1].State; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_Interrupt(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  | /* Make sure we are executing a process.  */ | 
|  | if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || | 
|  | cp->Killed) { | 
|  | KWSYSPE_DEBUG((stderr, "interrupt: child not executing\n")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Skip actually interrupting the child if it has already terminated.  */ | 
|  | if (cp->Terminated) { | 
|  | KWSYSPE_DEBUG((stderr, "interrupt: child already terminated\n")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Interrupt the children.  */ | 
|  | if (cp->CreateProcessGroup) { | 
|  | if (cp->ProcessInformation) { | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | /* Make sure the process handle isn't closed (e.g. from disowning). */ | 
|  | if (cp->ProcessInformation[i].hProcess) { | 
|  | /* The user created a process group for this process.  The group ID | 
|  | is the process ID for the original process in the group.  Note | 
|  | that we have to use Ctrl+Break: Ctrl+C is not allowed for process | 
|  | groups.  */ | 
|  | GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, | 
|  | cp->ProcessInformation[i].dwProcessId); | 
|  | } | 
|  | } | 
|  | } | 
|  | } else { | 
|  | /* No process group was created.  Kill our own process group...  */ | 
|  | GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void kwsysProcess_Kill(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  | /* Make sure we are executing a process.  */ | 
|  | if (!cp || cp->State != kwsysProcess_State_Executing || cp->TimeoutExpired || | 
|  | cp->Killed) { | 
|  | KWSYSPE_DEBUG((stderr, "kill: child not executing\n")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Disable the reading threads.  */ | 
|  | KWSYSPE_DEBUG((stderr, "kill: disabling pipe threads\n")); | 
|  | kwsysProcessDisablePipeThreads(cp); | 
|  |  | 
|  | /* Skip actually killing the child if it has already terminated.  */ | 
|  | if (cp->Terminated) { | 
|  | KWSYSPE_DEBUG((stderr, "kill: child already terminated\n")); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Kill the children.  */ | 
|  | cp->Killed = 1; | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | kwsysProcessKillTree(cp->ProcessInformation[i].dwProcessId); | 
|  | /* Remove from global list of processes and close handles.  */ | 
|  | kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); | 
|  | } | 
|  |  | 
|  | /* We are killing the children and ignoring all data.  Do not wait | 
|  | for them to exit.  */ | 
|  | } | 
|  |  | 
|  | void kwsysProcess_KillPID(unsigned long process_id) | 
|  | { | 
|  | kwsysProcessKillTree((DWORD)process_id); | 
|  | } | 
|  |  | 
|  | /* | 
|  | Function executed for each pipe's thread.  Argument is a pointer to | 
|  | the kwsysProcessPipeData instance for this thread. | 
|  | */ | 
|  | DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd) | 
|  | { | 
|  | kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; | 
|  | kwsysProcess* cp = td->Process; | 
|  |  | 
|  | /* Wait for a process to be ready.  */ | 
|  | while ((WaitForSingleObject(td->Reader.Ready, INFINITE), !cp->Deleting)) { | 
|  | /* Read output from the process for this thread's pipe.  */ | 
|  | kwsysProcessPipeThreadReadPipe(cp, td); | 
|  |  | 
|  | /* Signal the main thread we have reset for a new process.  */ | 
|  | ReleaseSemaphore(td->Reader.Reset, 1, 0); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | Function called in each pipe's thread to handle data for one | 
|  | execution of a subprocess. | 
|  | */ | 
|  | void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td) | 
|  | { | 
|  | /* Wait for space in the thread's buffer. */ | 
|  | while ((KWSYSPE_DEBUG((stderr, "wait for read %d\n", td->Index)), | 
|  | WaitForSingleObject(td->Reader.Go, INFINITE), !td->Closed)) { | 
|  | KWSYSPE_DEBUG((stderr, "reading %d\n", td->Index)); | 
|  |  | 
|  | /* Read data from the pipe.  This may block until data are available.  */ | 
|  | if (!ReadFile(td->Read, td->DataBuffer, KWSYSPE_PIPE_BUFFER_SIZE, | 
|  | &td->DataLength, 0)) { | 
|  | if (GetLastError() != ERROR_BROKEN_PIPE) { | 
|  | /* UNEXPECTED failure to read the pipe.  */ | 
|  | } | 
|  |  | 
|  | /* The pipe closed.  There are no more data to read.  */ | 
|  | td->Closed = 1; | 
|  | KWSYSPE_DEBUG((stderr, "read closed %d\n", td->Index)); | 
|  | } | 
|  |  | 
|  | KWSYSPE_DEBUG((stderr, "read %d\n", td->Index)); | 
|  |  | 
|  | /* Wait for our turn to be handled by the main thread.  */ | 
|  | WaitForSingleObject(cp->SharedIndexMutex, INFINITE); | 
|  |  | 
|  | KWSYSPE_DEBUG((stderr, "reporting read %d\n", td->Index)); | 
|  |  | 
|  | /* Tell the main thread we have something to report.  */ | 
|  | cp->SharedIndex = td->Index; | 
|  | ReleaseSemaphore(cp->Full, 1, 0); | 
|  | } | 
|  |  | 
|  | /* We were signalled to exit with our buffer empty.  Reset the | 
|  | mutex for a new process.  */ | 
|  | KWSYSPE_DEBUG((stderr, "self releasing reader %d\n", td->Index)); | 
|  | ReleaseSemaphore(td->Reader.Go, 1, 0); | 
|  | } | 
|  |  | 
|  | /* | 
|  | Function executed for each pipe's thread.  Argument is a pointer to | 
|  | the kwsysProcessPipeData instance for this thread. | 
|  | */ | 
|  | DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd) | 
|  | { | 
|  | kwsysProcessPipeData* td = (kwsysProcessPipeData*)ptd; | 
|  | kwsysProcess* cp = td->Process; | 
|  |  | 
|  | /* Wait for a process to be ready.  */ | 
|  | while ((WaitForSingleObject(td->Waker.Ready, INFINITE), !cp->Deleting)) { | 
|  | /* Wait for a possible wakeup.  */ | 
|  | kwsysProcessPipeThreadWakePipe(cp, td); | 
|  |  | 
|  | /* Signal the main thread we have reset for a new process.  */ | 
|  | ReleaseSemaphore(td->Waker.Reset, 1, 0); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | Function called in each pipe's thread to handle reading thread | 
|  | wakeup for one execution of a subprocess. | 
|  | */ | 
|  | void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp, kwsysProcessPipeData* td) | 
|  | { | 
|  | (void)cp; | 
|  |  | 
|  | /* Wait for a possible wake command. */ | 
|  | KWSYSPE_DEBUG((stderr, "wait for wake %d\n", td->Index)); | 
|  | WaitForSingleObject(td->Waker.Go, INFINITE); | 
|  | KWSYSPE_DEBUG((stderr, "waking %d\n", td->Index)); | 
|  |  | 
|  | /* If the pipe is not closed, we need to wake up the reading thread.  */ | 
|  | if (!td->Closed) { | 
|  | DWORD dummy; | 
|  | KWSYSPE_DEBUG((stderr, "waker %d writing byte\n", td->Index)); | 
|  | WriteFile(td->Write, "", 1, &dummy, 0); | 
|  | KWSYSPE_DEBUG((stderr, "waker %d wrote byte\n", td->Index)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Initialize a process control structure for kwsysProcess_Execute.  */ | 
|  | int kwsysProcessInitialize(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  | /* Reset internal status flags.  */ | 
|  | cp->TimeoutExpired = 0; | 
|  | cp->Terminated = 0; | 
|  | cp->Killed = 0; | 
|  |  | 
|  | free(cp->ProcessResults); | 
|  | /* Allocate process result information for each process.  */ | 
|  | cp->ProcessResults = (kwsysProcessResults*)malloc( | 
|  | sizeof(kwsysProcessResults) * (cp->NumberOfCommands)); | 
|  | if (!cp->ProcessResults) { | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(cp->ProcessResults, | 
|  | sizeof(kwsysProcessResults) * cp->NumberOfCommands); | 
|  | for (i = 0; i < cp->NumberOfCommands; i++) { | 
|  | cp->ProcessResults[i].ExitException = kwsysProcess_Exception_None; | 
|  | cp->ProcessResults[i].State = kwsysProcess_StateByIndex_Starting; | 
|  | cp->ProcessResults[i].ExitCode = 1; | 
|  | cp->ProcessResults[i].ExitValue = 1; | 
|  | strcpy(cp->ProcessResults[i].ExitExceptionString, "No exception"); | 
|  | } | 
|  |  | 
|  | /* Allocate process information for each process.  */ | 
|  | free(cp->ProcessInformation); | 
|  | cp->ProcessInformation = (PROCESS_INFORMATION*)malloc( | 
|  | sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); | 
|  | if (!cp->ProcessInformation) { | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(cp->ProcessInformation, | 
|  | sizeof(PROCESS_INFORMATION) * cp->NumberOfCommands); | 
|  | free(cp->CommandExitCodes); | 
|  | cp->CommandExitCodes = (DWORD*)malloc(sizeof(DWORD) * cp->NumberOfCommands); | 
|  | if (!cp->CommandExitCodes) { | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(cp->CommandExitCodes, sizeof(DWORD) * cp->NumberOfCommands); | 
|  |  | 
|  | /* Allocate event wait array.  The first event is cp->Full, the rest | 
|  | are the process termination events.  */ | 
|  | cp->ProcessEvents = | 
|  | (PHANDLE)malloc(sizeof(HANDLE) * (cp->NumberOfCommands + 1)); | 
|  | if (!cp->ProcessEvents) { | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(cp->ProcessEvents, sizeof(HANDLE) * (cp->NumberOfCommands + 1)); | 
|  | cp->ProcessEvents[0] = cp->Full; | 
|  | cp->ProcessEventsLength = cp->NumberOfCommands + 1; | 
|  |  | 
|  | /* Allocate space to save the real working directory of this process.  */ | 
|  | if (cp->WorkingDirectory) { | 
|  | cp->RealWorkingDirectoryLength = GetCurrentDirectoryW(0, 0); | 
|  | if (cp->RealWorkingDirectoryLength > 0) { | 
|  | cp->RealWorkingDirectory = | 
|  | malloc(cp->RealWorkingDirectoryLength * sizeof(wchar_t)); | 
|  | if (!cp->RealWorkingDirectory) { | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | } | 
|  | { | 
|  | for (i = 0; i < 3; ++i) { | 
|  | cp->PipeChildStd[i] = INVALID_HANDLE_VALUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static DWORD kwsysProcessCreateChildHandle(PHANDLE out, HANDLE in, int isStdIn) | 
|  | { | 
|  | DWORD flags; | 
|  |  | 
|  | /* Check whether the handle is valid for this process.  */ | 
|  | if (in != INVALID_HANDLE_VALUE && GetHandleInformation(in, &flags)) { | 
|  | /* Use the handle as-is if it is already inherited.  */ | 
|  | if (flags & HANDLE_FLAG_INHERIT) { | 
|  | *out = in; | 
|  | return ERROR_SUCCESS; | 
|  | } | 
|  |  | 
|  | /* Create an inherited copy of this handle.  */ | 
|  | if (DuplicateHandle(GetCurrentProcess(), in, GetCurrentProcess(), out, 0, | 
|  | TRUE, DUPLICATE_SAME_ACCESS)) { | 
|  | return ERROR_SUCCESS; | 
|  | } else { | 
|  | return GetLastError(); | 
|  | } | 
|  | } else { | 
|  | /* The given handle is not valid for this process.  Some child | 
|  | processes may break if they do not have a valid standard handle, | 
|  | so open NUL to give to the child.  */ | 
|  | SECURITY_ATTRIBUTES sa; | 
|  | ZeroMemory(&sa, sizeof(sa)); | 
|  | sa.nLength = (DWORD)sizeof(sa); | 
|  | sa.bInheritHandle = 1; | 
|  | *out = CreateFileW( | 
|  | L"NUL", | 
|  | (isStdIn ? GENERIC_READ : (GENERIC_WRITE | FILE_READ_ATTRIBUTES)), | 
|  | FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, 0); | 
|  | return (*out != INVALID_HANDLE_VALUE) ? ERROR_SUCCESS : GetLastError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | DWORD kwsysProcessCreate(kwsysProcess* cp, int index, | 
|  | kwsysProcessCreateInformation* si) | 
|  | { | 
|  | DWORD creationFlags; | 
|  | DWORD error = ERROR_SUCCESS; | 
|  |  | 
|  | /* Check if we are currently exiting.  */ | 
|  | if (!kwsysTryEnterCreateProcessSection()) { | 
|  | /* The Ctrl handler is currently working on exiting our process.  Rather | 
|  | than return an error code, which could cause incorrect conclusions to be | 
|  | reached by the caller, we simply hang.  (For example, a CMake try_run | 
|  | configure step might cause the project to configure wrong.)  */ | 
|  | Sleep(INFINITE); | 
|  | } | 
|  |  | 
|  | /* Create the child in a suspended state so we can wait until all | 
|  | children have been created before running any one.  */ | 
|  | creationFlags = CREATE_SUSPENDED; | 
|  | if (cp->CreateProcessGroup) { | 
|  | creationFlags |= CREATE_NEW_PROCESS_GROUP; | 
|  | } | 
|  |  | 
|  | /* Create inherited copies of the handles.  */ | 
|  | (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdInput, | 
|  | si->hStdInput, 1)) || | 
|  | (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdOutput, | 
|  | si->hStdOutput, 0)) || | 
|  | (error = kwsysProcessCreateChildHandle(&si->StartupInfo.hStdError, | 
|  | si->hStdError, 0)) || | 
|  | /* Create the process.  */ | 
|  | (!CreateProcessW(0, cp->Commands[index], 0, 0, TRUE, creationFlags, 0, 0, | 
|  | &si->StartupInfo, &cp->ProcessInformation[index]) && | 
|  | (error = GetLastError())); | 
|  |  | 
|  | /* Close the inherited copies of the handles. */ | 
|  | if (si->StartupInfo.hStdInput != si->hStdInput) { | 
|  | kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput); | 
|  | } | 
|  | if (si->StartupInfo.hStdOutput != si->hStdOutput) { | 
|  | kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); | 
|  | } | 
|  | if (si->StartupInfo.hStdError != si->hStdError) { | 
|  | kwsysProcessCleanupHandle(&si->StartupInfo.hStdError); | 
|  | } | 
|  |  | 
|  | /* Add the process to the global list of processes. */ | 
|  | if (!error && | 
|  | !kwsysProcessesAdd(cp->ProcessInformation[index].hProcess, | 
|  | cp->ProcessInformation[index].dwProcessId, | 
|  | cp->CreateProcessGroup)) { | 
|  | /* This failed for some reason.  Kill the suspended process. */ | 
|  | TerminateProcess(cp->ProcessInformation[index].hProcess, 1); | 
|  | /* And clean up... */ | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hThread); | 
|  | strcpy(cp->ErrorMessage, "kwsysProcessesAdd function failed"); | 
|  | error = ERROR_NOT_ENOUGH_MEMORY; /* Most likely reason.  */ | 
|  | } | 
|  |  | 
|  | /* If the console Ctrl handler is waiting for us, this will release it... */ | 
|  | kwsysLeaveCreateProcessSection(); | 
|  | return error; | 
|  | } | 
|  |  | 
|  | void kwsysProcessDestroy(kwsysProcess* cp, int event) | 
|  | { | 
|  | int i; | 
|  | int index; | 
|  |  | 
|  | /* Find the process index for the termination event.  */ | 
|  | for (index = 0; index < cp->NumberOfCommands; ++index) { | 
|  | if (cp->ProcessInformation[index].hProcess == cp->ProcessEvents[event]) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Check the exit code of the process.  */ | 
|  | GetExitCodeProcess(cp->ProcessInformation[index].hProcess, | 
|  | &cp->CommandExitCodes[index]); | 
|  |  | 
|  | /* Remove from global list of processes.  */ | 
|  | kwsysProcessesRemove(cp->ProcessInformation[index].hProcess); | 
|  |  | 
|  | /* Close the process handle for the terminated process.  */ | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[index].hProcess); | 
|  |  | 
|  | /* Remove the process from the available events.  */ | 
|  | cp->ProcessEventsLength -= 1; | 
|  | for (i = event; i < cp->ProcessEventsLength; ++i) { | 
|  | cp->ProcessEvents[i] = cp->ProcessEvents[i + 1]; | 
|  | } | 
|  |  | 
|  | /* Check if all processes have terminated.  */ | 
|  | if (cp->ProcessEventsLength == 1) { | 
|  | cp->Terminated = 1; | 
|  |  | 
|  | /* Close our copies of the pipe write handles so the pipe threads | 
|  | can detect end-of-data.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | /* TODO: If the child created its own child (our grandchild) | 
|  | which inherited a copy of the pipe write-end then the pipe | 
|  | may not close and we will still need the waker write pipe. | 
|  | However we still want to be able to detect end-of-data in the | 
|  | normal case.  The reader thread will have to switch to using | 
|  | PeekNamedPipe to read the last bit of data from the pipe | 
|  | without blocking.  This is equivalent to using a non-blocking | 
|  | read on posix.  */ | 
|  | KWSYSPE_DEBUG((stderr, "closing wakeup write %d\n", i)); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Write); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | DWORD kwsysProcessSetupOutputPipeFile(PHANDLE phandle, char const* name) | 
|  | { | 
|  | HANDLE fout; | 
|  | wchar_t* wname; | 
|  | DWORD error; | 
|  | if (!name) { | 
|  | return ERROR_INVALID_PARAMETER; | 
|  | } | 
|  |  | 
|  | /* Close the existing handle.  */ | 
|  | kwsysProcessCleanupHandle(phandle); | 
|  |  | 
|  | /* Create a handle to write a file for the pipe.  */ | 
|  | wname = kwsysEncoding_DupToWide(name); | 
|  | fout = | 
|  | CreateFileW(wname, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); | 
|  | error = GetLastError(); | 
|  | free(wname); | 
|  | if (fout == INVALID_HANDLE_VALUE) { | 
|  | return error; | 
|  | } | 
|  |  | 
|  | /* Assign the replacement handle.  */ | 
|  | *phandle = fout; | 
|  | return ERROR_SUCCESS; | 
|  | } | 
|  |  | 
|  | void kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle) | 
|  | { | 
|  | /* Close the existing handle.  */ | 
|  | kwsysProcessCleanupHandle(handle); | 
|  | /* Store the new standard handle.  */ | 
|  | *handle = GetStdHandle(nStdHandle); | 
|  | } | 
|  |  | 
|  | void kwsysProcessSetupPipeNative(HANDLE native, PHANDLE handle) | 
|  | { | 
|  | /* Close the existing handle.  */ | 
|  | kwsysProcessCleanupHandle(handle); | 
|  | /* Store the new given handle.  */ | 
|  | *handle = native; | 
|  | } | 
|  |  | 
|  | /* Close the given handle if it is open.  Reset its value to 0.  */ | 
|  | void kwsysProcessCleanupHandle(PHANDLE h) | 
|  | { | 
|  | if (h && *h && *h != INVALID_HANDLE_VALUE && | 
|  | *h != GetStdHandle(STD_INPUT_HANDLE) && | 
|  | *h != GetStdHandle(STD_OUTPUT_HANDLE) && | 
|  | *h != GetStdHandle(STD_ERROR_HANDLE)) { | 
|  | CloseHandle(*h); | 
|  | *h = INVALID_HANDLE_VALUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Close all handles created by kwsysProcess_Execute.  */ | 
|  | void kwsysProcessCleanup(kwsysProcess* cp, DWORD error) | 
|  | { | 
|  | int i; | 
|  | /* If this is an error case, report the error.  */ | 
|  | if (error) { | 
|  | /* Construct an error message if one has not been provided already.  */ | 
|  | if (cp->ErrorMessage[0] == 0) { | 
|  | /* Format the error message.  */ | 
|  | wchar_t err_msg[KWSYSPE_PIPE_BUFFER_SIZE]; | 
|  | DWORD length = FormatMessageW( | 
|  | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, error, | 
|  | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_msg, | 
|  | KWSYSPE_PIPE_BUFFER_SIZE, 0); | 
|  | if (length < 1) { | 
|  | /* FormatMessage failed.  Use a default message.  */ | 
|  | snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, | 
|  | "Process execution failed with error 0x%lX.  " | 
|  | "FormatMessage failed with error 0x%lX", | 
|  | error, GetLastError()); | 
|  | } | 
|  | if (!WideCharToMultiByte(CP_UTF8, 0, err_msg, -1, cp->ErrorMessage, | 
|  | KWSYSPE_PIPE_BUFFER_SIZE, NULL, NULL)) { | 
|  | /* WideCharToMultiByte failed.  Use a default message.  */ | 
|  | snprintf(cp->ErrorMessage, KWSYSPE_PIPE_BUFFER_SIZE, | 
|  | "Process execution failed with error 0x%lX.  " | 
|  | "WideCharToMultiByte failed with error 0x%lX", | 
|  | error, GetLastError()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Remove trailing period and newline, if any.  */ | 
|  | kwsysProcessCleanErrorMessage(cp); | 
|  |  | 
|  | /* Set the error state.  */ | 
|  | cp->State = kwsysProcess_State_Error; | 
|  |  | 
|  | /* Cleanup any processes already started in a suspended state.  */ | 
|  | if (cp->ProcessInformation) { | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | if (cp->ProcessInformation[i].hProcess) { | 
|  | TerminateProcess(cp->ProcessInformation[i].hProcess, 255); | 
|  | WaitForSingleObject(cp->ProcessInformation[i].hProcess, INFINITE); | 
|  | } | 
|  | } | 
|  | for (i = 0; i < cp->NumberOfCommands; ++i) { | 
|  | /* Remove from global list of processes and close handles.  */ | 
|  | kwsysProcessesRemove(cp->ProcessInformation[i].hProcess); | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread); | 
|  | kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Restore the working directory.  */ | 
|  | if (cp->RealWorkingDirectory) { | 
|  | SetCurrentDirectoryW(cp->RealWorkingDirectory); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Free memory.  */ | 
|  | if (cp->ProcessInformation) { | 
|  | free(cp->ProcessInformation); | 
|  | cp->ProcessInformation = 0; | 
|  | } | 
|  | if (cp->ProcessEvents) { | 
|  | free(cp->ProcessEvents); | 
|  | cp->ProcessEvents = 0; | 
|  | } | 
|  | if (cp->RealWorkingDirectory) { | 
|  | free(cp->RealWorkingDirectory); | 
|  | cp->RealWorkingDirectory = 0; | 
|  | } | 
|  |  | 
|  | /* Close each pipe.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Write); | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[i].Read); | 
|  | cp->Pipe[i].Closed = 0; | 
|  | } | 
|  | for (i = 0; i < 3; ++i) { | 
|  | kwsysProcessCleanupHandle(&cp->PipeChildStd[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void kwsysProcessCleanErrorMessage(kwsysProcess* cp) | 
|  | { | 
|  | /* Remove trailing period and newline, if any.  */ | 
|  | size_t length = strlen(cp->ErrorMessage); | 
|  | if (cp->ErrorMessage[length - 1] == '\n') { | 
|  | cp->ErrorMessage[length - 1] = 0; | 
|  | --length; | 
|  | if (length > 0 && cp->ErrorMessage[length - 1] == '\r') { | 
|  | cp->ErrorMessage[length - 1] = 0; | 
|  | --length; | 
|  | } | 
|  | } | 
|  | if (length > 0 && cp->ErrorMessage[length - 1] == '.') { | 
|  | cp->ErrorMessage[length - 1] = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Get the time at which either the process or user timeout will | 
|  | expire.  Returns 1 if the user timeout is first, and 0 otherwise.  */ | 
|  | int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout, | 
|  | kwsysProcessTime* timeoutTime) | 
|  | { | 
|  | /* The first time this is called, we need to calculate the time at | 
|  | which the child will timeout.  */ | 
|  | if (cp->Timeout && cp->TimeoutTime.QuadPart < 0) { | 
|  | kwsysProcessTime length = kwsysProcessTimeFromDouble(cp->Timeout); | 
|  | cp->TimeoutTime = kwsysProcessTimeAdd(cp->StartTime, length); | 
|  | } | 
|  |  | 
|  | /* Start with process timeout.  */ | 
|  | *timeoutTime = cp->TimeoutTime; | 
|  |  | 
|  | /* Check if the user timeout is earlier.  */ | 
|  | if (userTimeout) { | 
|  | kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); | 
|  | kwsysProcessTime userTimeoutLength = | 
|  | kwsysProcessTimeFromDouble(*userTimeout); | 
|  | kwsysProcessTime userTimeoutTime = | 
|  | kwsysProcessTimeAdd(currentTime, userTimeoutLength); | 
|  | if (timeoutTime->QuadPart < 0 || | 
|  | kwsysProcessTimeLess(userTimeoutTime, *timeoutTime)) { | 
|  | *timeoutTime = userTimeoutTime; | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Get the length of time before the given timeout time arrives. | 
|  | Returns 1 if the time has already arrived, and 0 otherwise.  */ | 
|  | int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, | 
|  | double* userTimeout, | 
|  | kwsysProcessTime* timeoutLength) | 
|  | { | 
|  | if (timeoutTime->QuadPart < 0) { | 
|  | /* No timeout time has been requested.  */ | 
|  | return 0; | 
|  | } else { | 
|  | /* Calculate the remaining time.  */ | 
|  | kwsysProcessTime currentTime = kwsysProcessTimeGetCurrent(); | 
|  | *timeoutLength = kwsysProcessTimeSubtract(*timeoutTime, currentTime); | 
|  |  | 
|  | if (timeoutLength->QuadPart < 0 && userTimeout && *userTimeout <= 0) { | 
|  | /* Caller has explicitly requested a zero timeout.  */ | 
|  | timeoutLength->QuadPart = 0; | 
|  | } | 
|  |  | 
|  | if (timeoutLength->QuadPart < 0) { | 
|  | /* Timeout has already expired.  */ | 
|  | return 1; | 
|  | } else { | 
|  | /* There is some time left.  */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | kwsysProcessTime kwsysProcessTimeGetCurrent() | 
|  | { | 
|  | kwsysProcessTime current; | 
|  | FILETIME ft; | 
|  | GetSystemTimeAsFileTime(&ft); | 
|  | current.LowPart = ft.dwLowDateTime; | 
|  | current.HighPart = ft.dwHighDateTime; | 
|  | return current; | 
|  | } | 
|  |  | 
|  | DWORD kwsysProcessTimeToDWORD(kwsysProcessTime t) | 
|  | { | 
|  | return (DWORD)(t.QuadPart * 0.0001); | 
|  | } | 
|  |  | 
|  | double kwsysProcessTimeToDouble(kwsysProcessTime t) | 
|  | { | 
|  | return t.QuadPart * 0.0000001; | 
|  | } | 
|  |  | 
|  | kwsysProcessTime kwsysProcessTimeFromDouble(double d) | 
|  | { | 
|  | kwsysProcessTime t; | 
|  | t.QuadPart = (LONGLONG)(d * 10000000); | 
|  | return t; | 
|  | } | 
|  |  | 
|  | int kwsysProcessTimeLess(kwsysProcessTime in1, kwsysProcessTime in2) | 
|  | { | 
|  | return in1.QuadPart < in2.QuadPart; | 
|  | } | 
|  |  | 
|  | kwsysProcessTime kwsysProcessTimeAdd(kwsysProcessTime in1, | 
|  | kwsysProcessTime in2) | 
|  | { | 
|  | kwsysProcessTime out; | 
|  | out.QuadPart = in1.QuadPart + in2.QuadPart; | 
|  | return out; | 
|  | } | 
|  |  | 
|  | kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, | 
|  | kwsysProcessTime in2) | 
|  | { | 
|  | kwsysProcessTime out; | 
|  | out.QuadPart = in1.QuadPart - in2.QuadPart; | 
|  | return out; | 
|  | } | 
|  |  | 
|  | #define KWSYSPE_CASE(type, str)                                               \ | 
|  | cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_##type;      \ | 
|  | strcpy(cp->ProcessResults[idx].ExitExceptionString, str) | 
|  | static void kwsysProcessSetExitExceptionByIndex(kwsysProcess* cp, int code, | 
|  | int idx) | 
|  | { | 
|  | switch (code) { | 
|  | case STATUS_CONTROL_C_EXIT: | 
|  | KWSYSPE_CASE(Interrupt, "User interrupt"); | 
|  | break; | 
|  |  | 
|  | case STATUS_FLOAT_DENORMAL_OPERAND: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point exception (denormal operand)"); | 
|  | break; | 
|  | case STATUS_FLOAT_DIVIDE_BY_ZERO: | 
|  | KWSYSPE_CASE(Numerical, "Divide-by-zero"); | 
|  | break; | 
|  | case STATUS_FLOAT_INEXACT_RESULT: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point exception (inexact result)"); | 
|  | break; | 
|  | case STATUS_FLOAT_INVALID_OPERATION: | 
|  | KWSYSPE_CASE(Numerical, "Invalid floating-point operation"); | 
|  | break; | 
|  | case STATUS_FLOAT_OVERFLOW: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point overflow"); | 
|  | break; | 
|  | case STATUS_FLOAT_STACK_CHECK: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point stack check failed"); | 
|  | break; | 
|  | case STATUS_FLOAT_UNDERFLOW: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point underflow"); | 
|  | break; | 
|  | #ifdef STATUS_FLOAT_MULTIPLE_FAULTS | 
|  | case STATUS_FLOAT_MULTIPLE_FAULTS: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point exception (multiple faults)"); | 
|  | break; | 
|  | #endif | 
|  | #ifdef STATUS_FLOAT_MULTIPLE_TRAPS | 
|  | case STATUS_FLOAT_MULTIPLE_TRAPS: | 
|  | KWSYSPE_CASE(Numerical, "Floating-point exception (multiple traps)"); | 
|  | break; | 
|  | #endif | 
|  | case STATUS_INTEGER_DIVIDE_BY_ZERO: | 
|  | KWSYSPE_CASE(Numerical, "Integer divide-by-zero"); | 
|  | break; | 
|  | case STATUS_INTEGER_OVERFLOW: | 
|  | KWSYSPE_CASE(Numerical, "Integer overflow"); | 
|  | break; | 
|  |  | 
|  | case STATUS_DATATYPE_MISALIGNMENT: | 
|  | KWSYSPE_CASE(Fault, "Datatype misalignment"); | 
|  | break; | 
|  | case STATUS_ACCESS_VIOLATION: | 
|  | KWSYSPE_CASE(Fault, "Access violation"); | 
|  | break; | 
|  | case STATUS_IN_PAGE_ERROR: | 
|  | KWSYSPE_CASE(Fault, "In-page error"); | 
|  | break; | 
|  | case STATUS_INVALID_HANDLE: | 
|  | KWSYSPE_CASE(Fault, "Invalid handle"); | 
|  | break; | 
|  | case STATUS_NONCONTINUABLE_EXCEPTION: | 
|  | KWSYSPE_CASE(Fault, "Noncontinuable exception"); | 
|  | break; | 
|  | case STATUS_INVALID_DISPOSITION: | 
|  | KWSYSPE_CASE(Fault, "Invalid disposition"); | 
|  | break; | 
|  | case STATUS_ARRAY_BOUNDS_EXCEEDED: | 
|  | KWSYSPE_CASE(Fault, "Array bounds exceeded"); | 
|  | break; | 
|  | case STATUS_STACK_OVERFLOW: | 
|  | KWSYSPE_CASE(Fault, "Stack overflow"); | 
|  | break; | 
|  |  | 
|  | case STATUS_ILLEGAL_INSTRUCTION: | 
|  | KWSYSPE_CASE(Illegal, "Illegal instruction"); | 
|  | break; | 
|  | case STATUS_PRIVILEGED_INSTRUCTION: | 
|  | KWSYSPE_CASE(Illegal, "Privileged instruction"); | 
|  | break; | 
|  |  | 
|  | case STATUS_NO_MEMORY: | 
|  | default: | 
|  | cp->ProcessResults[idx].ExitException = kwsysProcess_Exception_Other; | 
|  | snprintf(cp->ProcessResults[idx].ExitExceptionString, | 
|  | KWSYSPE_PIPE_BUFFER_SIZE, "Exit code 0x%x\n", code); | 
|  | break; | 
|  | } | 
|  | } | 
|  | #undef KWSYSPE_CASE | 
|  |  | 
|  | typedef struct kwsysProcess_List_s kwsysProcess_List; | 
|  | static kwsysProcess_List* kwsysProcess_List_New(void); | 
|  | static void kwsysProcess_List_Delete(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List_Update(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List_NextProcess(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self); | 
|  |  | 
|  | /* Windows NT 4 API definitions.  */ | 
|  | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) | 
|  | typedef LONG NTSTATUS; | 
|  | typedef LONG KPRIORITY; | 
|  | typedef struct _UNICODE_STRING UNICODE_STRING; | 
|  | struct _UNICODE_STRING | 
|  | { | 
|  | USHORT Length; | 
|  | USHORT MaximumLength; | 
|  | PWSTR Buffer; | 
|  | }; | 
|  |  | 
|  | /* The process information structure.  Declare only enough to get | 
|  | process identifiers.  The rest may be ignored because we use the | 
|  | NextEntryDelta to move through an array of instances.  */ | 
|  | typedef struct _SYSTEM_PROCESS_INFORMATION SYSTEM_PROCESS_INFORMATION; | 
|  | typedef SYSTEM_PROCESS_INFORMATION* PSYSTEM_PROCESS_INFORMATION; | 
|  | struct _SYSTEM_PROCESS_INFORMATION | 
|  | { | 
|  | ULONG NextEntryDelta; | 
|  | ULONG ThreadCount; | 
|  | ULONG Reserved1[6]; | 
|  | LARGE_INTEGER CreateTime; | 
|  | LARGE_INTEGER UserTime; | 
|  | LARGE_INTEGER KernelTime; | 
|  | UNICODE_STRING ProcessName; | 
|  | KPRIORITY BasePriority; | 
|  | ULONG ProcessId; | 
|  | ULONG InheritedFromProcessId; | 
|  | }; | 
|  |  | 
|  | /* Toolhelp32 API definitions.  */ | 
|  | #define TH32CS_SNAPPROCESS 0x00000002 | 
|  | #if defined(_WIN64) | 
|  | typedef unsigned __int64 ProcessULONG_PTR; | 
|  | #else | 
|  | typedef unsigned long ProcessULONG_PTR; | 
|  | #endif | 
|  | typedef struct tagPROCESSENTRY32 PROCESSENTRY32; | 
|  | typedef PROCESSENTRY32* LPPROCESSENTRY32; | 
|  | struct tagPROCESSENTRY32 | 
|  | { | 
|  | DWORD dwSize; | 
|  | DWORD cntUsage; | 
|  | DWORD th32ProcessID; | 
|  | ProcessULONG_PTR th32DefaultHeapID; | 
|  | DWORD th32ModuleID; | 
|  | DWORD cntThreads; | 
|  | DWORD th32ParentProcessID; | 
|  | LONG pcPriClassBase; | 
|  | DWORD dwFlags; | 
|  | char szExeFile[MAX_PATH]; | 
|  | }; | 
|  |  | 
|  | /* Windows API function types.  */ | 
|  | typedef HANDLE(WINAPI* CreateToolhelp32SnapshotType)(DWORD, DWORD); | 
|  | typedef BOOL(WINAPI* Process32FirstType)(HANDLE, LPPROCESSENTRY32); | 
|  | typedef BOOL(WINAPI* Process32NextType)(HANDLE, LPPROCESSENTRY32); | 
|  | typedef NTSTATUS(WINAPI* ZwQuerySystemInformationType)(ULONG, PVOID, ULONG, | 
|  | PULONG); | 
|  |  | 
|  | static int kwsysProcess_List__New_NT4(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self); | 
|  | static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self); | 
|  | static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self); | 
|  | static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self); | 
|  |  | 
|  | struct kwsysProcess_List_s | 
|  | { | 
|  | /* Implementation switches at runtime based on version of Windows.  */ | 
|  | int NT4; | 
|  |  | 
|  | /* Implementation functions and data for NT 4.  */ | 
|  | ZwQuerySystemInformationType P_ZwQuerySystemInformation; | 
|  | char* Buffer; | 
|  | int BufferSize; | 
|  | PSYSTEM_PROCESS_INFORMATION CurrentInfo; | 
|  |  | 
|  | /* Implementation functions and data for other Windows versions.  */ | 
|  | CreateToolhelp32SnapshotType P_CreateToolhelp32Snapshot; | 
|  | Process32FirstType P_Process32First; | 
|  | Process32NextType P_Process32Next; | 
|  | HANDLE Snapshot; | 
|  | PROCESSENTRY32 CurrentEntry; | 
|  | }; | 
|  |  | 
|  | static kwsysProcess_List* kwsysProcess_List_New(void) | 
|  | { | 
|  | OSVERSIONINFO osv; | 
|  | kwsysProcess_List* self; | 
|  |  | 
|  | /* Allocate and initialize the list object.  */ | 
|  | if (!(self = (kwsysProcess_List*)malloc(sizeof(kwsysProcess_List)))) { | 
|  | return 0; | 
|  | } | 
|  | memset(self, 0, sizeof(*self)); | 
|  |  | 
|  | /* Select an implementation.  */ | 
|  | ZeroMemory(&osv, sizeof(osv)); | 
|  | osv.dwOSVersionInfoSize = sizeof(osv); | 
|  | #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx | 
|  | #  pragma warning(push) | 
|  | #  ifdef __INTEL_COMPILER | 
|  | #    pragma warning(disable : 1478) | 
|  | #  elif defined __clang__ | 
|  | #    pragma clang diagnostic push | 
|  | #    pragma clang diagnostic ignored "-Wdeprecated-declarations" | 
|  | #  else | 
|  | #    pragma warning(disable : 4996) | 
|  | #  endif | 
|  | #endif | 
|  | GetVersionEx(&osv); | 
|  | #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx | 
|  | #  ifdef __clang__ | 
|  | #    pragma clang diagnostic pop | 
|  | #  else | 
|  | #    pragma warning(pop) | 
|  | #  endif | 
|  | #endif | 
|  | self->NT4 = | 
|  | (osv.dwPlatformId == VER_PLATFORM_WIN32_NT && osv.dwMajorVersion < 5) ? 1 | 
|  | : 0; | 
|  |  | 
|  | /* Initialize the selected implementation.  */ | 
|  | if (!(self->NT4 ? kwsysProcess_List__New_NT4(self) | 
|  | : kwsysProcess_List__New_Snapshot(self))) { | 
|  | kwsysProcess_List_Delete(self); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Update to the current set of processes.  */ | 
|  | if (!kwsysProcess_List_Update(self)) { | 
|  | kwsysProcess_List_Delete(self); | 
|  | return 0; | 
|  | } | 
|  | return self; | 
|  | } | 
|  |  | 
|  | static void kwsysProcess_List_Delete(kwsysProcess_List* self) | 
|  | { | 
|  | if (self) { | 
|  | if (self->NT4) { | 
|  | kwsysProcess_List__Delete_NT4(self); | 
|  | } else { | 
|  | kwsysProcess_List__Delete_Snapshot(self); | 
|  | } | 
|  | free(self); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List_Update(kwsysProcess_List* self) | 
|  | { | 
|  | return self ? (self->NT4 ? kwsysProcess_List__Update_NT4(self) | 
|  | : kwsysProcess_List__Update_Snapshot(self)) | 
|  | : 0; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List_GetCurrentProcessId(kwsysProcess_List* self) | 
|  | { | 
|  | return self ? (self->NT4 ? kwsysProcess_List__GetProcessId_NT4(self) | 
|  | : kwsysProcess_List__GetProcessId_Snapshot(self)) | 
|  | : -1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List_GetCurrentParentId(kwsysProcess_List* self) | 
|  | { | 
|  | return self ? (self->NT4 ? kwsysProcess_List__GetParentId_NT4(self) | 
|  | : kwsysProcess_List__GetParentId_Snapshot(self)) | 
|  | : -1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List_NextProcess(kwsysProcess_List* self) | 
|  | { | 
|  | return (self ? (self->NT4 ? kwsysProcess_List__Next_NT4(self) | 
|  | : kwsysProcess_List__Next_Snapshot(self)) | 
|  | : 0); | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__New_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | /* Get a handle to the NT runtime module that should already be | 
|  | loaded in this program.  This does not actually increment the | 
|  | reference count to the module so we do not need to close the | 
|  | handle.  */ | 
|  | HMODULE hNT = GetModuleHandleW(L"ntdll.dll"); | 
|  | if (hNT) { | 
|  | /* Get pointers to the needed API functions.  */ | 
|  | self->P_ZwQuerySystemInformation = | 
|  | ((ZwQuerySystemInformationType)GetProcAddress( | 
|  | hNT, "ZwQuerySystemInformation")); | 
|  | } | 
|  | if (!self->P_ZwQuerySystemInformation) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Allocate an initial process information buffer.  */ | 
|  | self->BufferSize = 32768; | 
|  | self->Buffer = (char*)malloc(self->BufferSize); | 
|  | return self->Buffer ? 1 : 0; | 
|  | } | 
|  |  | 
|  | static void kwsysProcess_List__Delete_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | /* Free the process information buffer.  */ | 
|  | free(self->Buffer); | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__Update_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | self->CurrentInfo = 0; | 
|  | for (;;) { | 
|  | /* Query number 5 is for system process list.  */ | 
|  | NTSTATUS status = | 
|  | self->P_ZwQuerySystemInformation(5, self->Buffer, self->BufferSize, 0); | 
|  | if (status == STATUS_INFO_LENGTH_MISMATCH) { | 
|  | /* The query requires a bigger buffer.  */ | 
|  | int newBufferSize = self->BufferSize * 2; | 
|  | char* newBuffer = (char*)malloc(newBufferSize); | 
|  | if (newBuffer) { | 
|  | free(self->Buffer); | 
|  | self->Buffer = newBuffer; | 
|  | self->BufferSize = newBufferSize; | 
|  | } else { | 
|  | return 0; | 
|  | } | 
|  | } else if (status >= 0) { | 
|  | /* The query succeeded.  Initialize traversal of the process list.  */ | 
|  | self->CurrentInfo = (PSYSTEM_PROCESS_INFORMATION)self->Buffer; | 
|  | return 1; | 
|  | } else { | 
|  | /* The query failed.  */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__Next_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | if (self->CurrentInfo) { | 
|  | if (self->CurrentInfo->NextEntryDelta > 0) { | 
|  | self->CurrentInfo = | 
|  | ((PSYSTEM_PROCESS_INFORMATION)((char*)self->CurrentInfo + | 
|  | self->CurrentInfo->NextEntryDelta)); | 
|  | return 1; | 
|  | } | 
|  | self->CurrentInfo = 0; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__GetProcessId_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | return self->CurrentInfo ? self->CurrentInfo->ProcessId : -1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__GetParentId_NT4(kwsysProcess_List* self) | 
|  | { | 
|  | return self->CurrentInfo ? self->CurrentInfo->InheritedFromProcessId : -1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__New_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | /* Get a handle to the Windows runtime module that should already be | 
|  | loaded in this program.  This does not actually increment the | 
|  | reference count to the module so we do not need to close the | 
|  | handle.  */ | 
|  | HMODULE hKernel = GetModuleHandleW(L"kernel32.dll"); | 
|  | if (hKernel) { | 
|  | self->P_CreateToolhelp32Snapshot = | 
|  | ((CreateToolhelp32SnapshotType)GetProcAddress( | 
|  | hKernel, "CreateToolhelp32Snapshot")); | 
|  | self->P_Process32First = | 
|  | ((Process32FirstType)GetProcAddress(hKernel, "Process32First")); | 
|  | self->P_Process32Next = | 
|  | ((Process32NextType)GetProcAddress(hKernel, "Process32Next")); | 
|  | } | 
|  | return (self->P_CreateToolhelp32Snapshot && self->P_Process32First && | 
|  | self->P_Process32Next) | 
|  | ? 1 | 
|  | : 0; | 
|  | } | 
|  |  | 
|  | static void kwsysProcess_List__Delete_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | if (self->Snapshot) { | 
|  | CloseHandle(self->Snapshot); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__Update_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | if (self->Snapshot) { | 
|  | CloseHandle(self->Snapshot); | 
|  | } | 
|  | if (!(self->Snapshot = | 
|  | self->P_CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { | 
|  | return 0; | 
|  | } | 
|  | ZeroMemory(&self->CurrentEntry, sizeof(self->CurrentEntry)); | 
|  | self->CurrentEntry.dwSize = sizeof(self->CurrentEntry); | 
|  | if (!self->P_Process32First(self->Snapshot, &self->CurrentEntry)) { | 
|  | CloseHandle(self->Snapshot); | 
|  | self->Snapshot = 0; | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__Next_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | if (self->Snapshot) { | 
|  | if (self->P_Process32Next(self->Snapshot, &self->CurrentEntry)) { | 
|  | return 1; | 
|  | } | 
|  | CloseHandle(self->Snapshot); | 
|  | self->Snapshot = 0; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__GetProcessId_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | return self->Snapshot ? self->CurrentEntry.th32ProcessID : -1; | 
|  | } | 
|  |  | 
|  | static int kwsysProcess_List__GetParentId_Snapshot(kwsysProcess_List* self) | 
|  | { | 
|  | return self->Snapshot ? self->CurrentEntry.th32ParentProcessID : -1; | 
|  | } | 
|  |  | 
|  | static void kwsysProcessKill(DWORD pid) | 
|  | { | 
|  | HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid); | 
|  | if (h) { | 
|  | TerminateProcess(h, 255); | 
|  | WaitForSingleObject(h, INFINITE); | 
|  | CloseHandle(h); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void kwsysProcessKillTree(int pid) | 
|  | { | 
|  | kwsysProcess_List* plist = kwsysProcess_List_New(); | 
|  | kwsysProcessKill(pid); | 
|  | if (plist) { | 
|  | do { | 
|  | if (kwsysProcess_List_GetCurrentParentId(plist) == pid) { | 
|  | int ppid = kwsysProcess_List_GetCurrentProcessId(plist); | 
|  | kwsysProcessKillTree(ppid); | 
|  | } | 
|  | } while (kwsysProcess_List_NextProcess(plist)); | 
|  | kwsysProcess_List_Delete(plist); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void kwsysProcessDisablePipeThreads(kwsysProcess* cp) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* If data were just reported data, release the pipe's thread.  */ | 
|  | if (cp->CurrentIndex < KWSYSPE_PIPE_COUNT) { | 
|  | KWSYSPE_DEBUG((stderr, "releasing reader %d\n", cp->CurrentIndex)); | 
|  | ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); | 
|  | cp->CurrentIndex = KWSYSPE_PIPE_COUNT; | 
|  | } | 
|  |  | 
|  | /* Wakeup all reading threads that are not on closed pipes.  */ | 
|  | for (i = 0; i < KWSYSPE_PIPE_COUNT; ++i) { | 
|  | /* The wakeup threads will write one byte to the pipe write ends. | 
|  | If there are no data in the pipe then this is enough to wakeup | 
|  | the reading threads.  If there are already data in the pipe | 
|  | this may block.  We cannot use PeekNamedPipe to check whether | 
|  | there are data because an outside process might still be | 
|  | writing data if we are disowning it.  Also, PeekNamedPipe will | 
|  | block if checking a pipe on which the reading thread is | 
|  | currently calling ReadPipe.  Therefore we need a separate | 
|  | thread to call WriteFile.  If it blocks, that is okay because | 
|  | it will unblock when we close the read end and break the pipe | 
|  | below.  */ | 
|  | if (cp->Pipe[i].Read) { | 
|  | KWSYSPE_DEBUG((stderr, "releasing waker %d\n", i)); | 
|  | ReleaseSemaphore(cp->Pipe[i].Waker.Go, 1, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Tell pipe threads to reset until we run another process.  */ | 
|  | while (cp->PipesLeft > 0) { | 
|  | /* The waking threads will cause all reading threads to report. | 
|  | Wait for the next one and save its index.  */ | 
|  | KWSYSPE_DEBUG((stderr, "waiting for reader\n")); | 
|  | WaitForSingleObject(cp->Full, INFINITE); | 
|  | cp->CurrentIndex = cp->SharedIndex; | 
|  | ReleaseSemaphore(cp->SharedIndexMutex, 1, 0); | 
|  | KWSYSPE_DEBUG((stderr, "got reader %d\n", cp->CurrentIndex)); | 
|  |  | 
|  | /* We are done reading this pipe.  Close its read handle.  */ | 
|  | cp->Pipe[cp->CurrentIndex].Closed = 1; | 
|  | kwsysProcessCleanupHandle(&cp->Pipe[cp->CurrentIndex].Read); | 
|  | --cp->PipesLeft; | 
|  |  | 
|  | /* Tell the reading thread we are done with the data.  It will | 
|  | reset immediately because the pipe is closed.  */ | 
|  | ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Global set of executing processes for use by the Ctrl handler. | 
|  | This global instance will be zero-initialized by the compiler. | 
|  |  | 
|  | Note that the console Ctrl handler runs on a background thread and so | 
|  | everything it does must be thread safe.  Here, we track the hProcess | 
|  | HANDLEs directly instead of kwsysProcess instances, so that we don't have | 
|  | to make kwsysProcess thread safe.  */ | 
|  | typedef struct kwsysProcessInstance_s | 
|  | { | 
|  | HANDLE hProcess; | 
|  | DWORD dwProcessId; | 
|  | int NewProcessGroup; /* Whether the process was created in a new group.  */ | 
|  | } kwsysProcessInstance; | 
|  |  | 
|  | typedef struct kwsysProcessInstances_s | 
|  | { | 
|  | /* Whether we have initialized key fields below, like critical sections.  */ | 
|  | int Initialized; | 
|  |  | 
|  | /* Ctrl handler runs on a different thread, so we must sync access.  */ | 
|  | CRITICAL_SECTION Lock; | 
|  |  | 
|  | int Exiting; | 
|  | size_t Count; | 
|  | size_t Size; | 
|  | kwsysProcessInstance* Processes; | 
|  | } kwsysProcessInstances; | 
|  | static kwsysProcessInstances kwsysProcesses; | 
|  |  | 
|  | /* Initialize critial section and set up console Ctrl handler.  You MUST call | 
|  | this before using any other kwsysProcesses* functions below.  */ | 
|  | static int kwsysProcessesInitialize(void) | 
|  | { | 
|  | /* Initialize everything if not done already.  */ | 
|  | if (!kwsysProcesses.Initialized) { | 
|  | InitializeCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | /* Set up console ctrl handler.  */ | 
|  | if (!SetConsoleCtrlHandler(kwsysCtrlHandler, TRUE)) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | kwsysProcesses.Initialized = 1; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* The Ctrl handler waits on the global list of processes.  To prevent an | 
|  | orphaned process, do not create a new process if the Ctrl handler is | 
|  | already running.  Do so by using this function to check if it is ok to | 
|  | create a process.  */ | 
|  | static int kwsysTryEnterCreateProcessSection(void) | 
|  | { | 
|  | /* Enter main critical section; this means creating a process and the Ctrl | 
|  | handler are mutually exclusive.  */ | 
|  | EnterCriticalSection(&kwsysProcesses.Lock); | 
|  | /* Indicate to the caller if they can create a process.  */ | 
|  | if (kwsysProcesses.Exiting) { | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  | return 0; | 
|  | } else { | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Matching function on successful kwsysTryEnterCreateProcessSection return. | 
|  | Make sure you called kwsysProcessesAdd if applicable before calling this.*/ | 
|  | static void kwsysLeaveCreateProcessSection(void) | 
|  | { | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  | } | 
|  |  | 
|  | /* Add new process to global process list.  The Ctrl handler will wait for | 
|  | the process to exit before it returns.  Do not close the process handle | 
|  | until after calling kwsysProcessesRemove.  The newProcessGroup parameter | 
|  | must be set if the process was created with CREATE_NEW_PROCESS_GROUP.  */ | 
|  | static int kwsysProcessesAdd(HANDLE hProcess, DWORD dwProcessid, | 
|  | int newProcessGroup) | 
|  | { | 
|  | if (!kwsysProcessesInitialize() || !hProcess || | 
|  | hProcess == INVALID_HANDLE_VALUE) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Enter the critical section. */ | 
|  | EnterCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | /* Make sure there is enough space for the new process handle.  */ | 
|  | if (kwsysProcesses.Count == kwsysProcesses.Size) { | 
|  | size_t newSize; | 
|  | kwsysProcessInstance* newArray; | 
|  | /* Start with enough space for a small number of process handles | 
|  | and double the size each time more is needed.  */ | 
|  | newSize = kwsysProcesses.Size ? kwsysProcesses.Size * 2 : 4; | 
|  |  | 
|  | /* Try allocating the new block of memory.  */ | 
|  | if ((newArray = (kwsysProcessInstance*)malloc( | 
|  | newSize * sizeof(kwsysProcessInstance)))) { | 
|  | /* Copy the old process handles to the new memory.  */ | 
|  | if (kwsysProcesses.Count > 0) { | 
|  | memcpy(newArray, kwsysProcesses.Processes, | 
|  | kwsysProcesses.Count * sizeof(kwsysProcessInstance)); | 
|  | } | 
|  | } else { | 
|  | /* Failed to allocate memory for the new process handle set.  */ | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Free original array. */ | 
|  | free(kwsysProcesses.Processes); | 
|  |  | 
|  | /* Update original structure with new allocation. */ | 
|  | kwsysProcesses.Size = newSize; | 
|  | kwsysProcesses.Processes = newArray; | 
|  | } | 
|  |  | 
|  | /* Append the new process information to the set.  */ | 
|  | kwsysProcesses.Processes[kwsysProcesses.Count].hProcess = hProcess; | 
|  | kwsysProcesses.Processes[kwsysProcesses.Count].dwProcessId = dwProcessid; | 
|  | kwsysProcesses.Processes[kwsysProcesses.Count++].NewProcessGroup = | 
|  | newProcessGroup; | 
|  |  | 
|  | /* Leave critical section and return success. */ | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Removes process to global process list.  */ | 
|  | static void kwsysProcessesRemove(HANDLE hProcess) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | if (!hProcess || hProcess == INVALID_HANDLE_VALUE) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | EnterCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | /* Find the given process in the set.  */ | 
|  | for (i = 0; i < kwsysProcesses.Count; ++i) { | 
|  | if (kwsysProcesses.Processes[i].hProcess == hProcess) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (i < kwsysProcesses.Count) { | 
|  | /* Found it!  Remove the process from the set.  */ | 
|  | --kwsysProcesses.Count; | 
|  | for (; i < kwsysProcesses.Count; ++i) { | 
|  | kwsysProcesses.Processes[i] = kwsysProcesses.Processes[i + 1]; | 
|  | } | 
|  |  | 
|  | /* If this was the last process, free the array.  */ | 
|  | if (kwsysProcesses.Count == 0) { | 
|  | kwsysProcesses.Size = 0; | 
|  | free(kwsysProcesses.Processes); | 
|  | kwsysProcesses.Processes = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  | } | 
|  |  | 
|  | static BOOL WINAPI kwsysCtrlHandler(DWORD dwCtrlType) | 
|  | { | 
|  | size_t i; | 
|  | (void)dwCtrlType; | 
|  | /* Enter critical section.  */ | 
|  | EnterCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | /* Set flag indicating that we are exiting.  */ | 
|  | kwsysProcesses.Exiting = 1; | 
|  |  | 
|  | /* If some of our processes were created in a new process group, we must | 
|  | manually interrupt them.  They won't otherwise receive a Ctrl+C/Break. */ | 
|  | for (i = 0; i < kwsysProcesses.Count; ++i) { | 
|  | if (kwsysProcesses.Processes[i].NewProcessGroup) { | 
|  | DWORD groupId = kwsysProcesses.Processes[i].dwProcessId; | 
|  | if (groupId) { | 
|  | GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, groupId); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Wait for each child process to exit.  This is the key step that prevents | 
|  | us from leaving several orphaned children processes running in the | 
|  | background when the user presses Ctrl+C.  */ | 
|  | for (i = 0; i < kwsysProcesses.Count; ++i) { | 
|  | WaitForSingleObject(kwsysProcesses.Processes[i].hProcess, INFINITE); | 
|  | } | 
|  |  | 
|  | /* Leave critical section.  */ | 
|  | LeaveCriticalSection(&kwsysProcesses.Lock); | 
|  |  | 
|  | /* Continue on to default Ctrl handler (which calls ExitProcess).  */ | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | void kwsysProcess_ResetStartTime(kwsysProcess* cp) | 
|  | { | 
|  | if (!cp) { | 
|  | return; | 
|  | } | 
|  | /* Reset start time. */ | 
|  | cp->StartTime = kwsysProcessTimeGetCurrent(); | 
|  | } |