ProcessWin32.c 85.8 KB
Newer Older
1 2
/*=========================================================================

Brad King's avatar
Brad King committed
3 4 5 6 7 8 9 10 11
  Program:   KWSys - Kitware System Library
  Module:    ProcessWin32.c

  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.
12 13

=========================================================================*/
14 15
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Process.h)
16

17 18 19 20 21 22
/* Work-around CMake dependency scanning limitation.  This must
   duplicate the above list of headers.  */
#if 0
# include "Process.h.in"
#endif

23 24 25
/*

Implementation for Windows
26

27 28 29
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.
30

31 32 33 34
On Windows9x platforms, a small WIN32 console application is spawned
in-between the calling process and the actual child to be executed.
This is to work-around a problem with connecting pipes from WIN16
console applications to WIN32 applications.
35

36 37 38 39 40
For more information, please check Microsoft Knowledge Base Articles
Q190351 and Q150956.

*/

41 42 43
#ifdef _MSC_VER
#pragma warning (push, 1)
#endif
44 45 46 47
#include <windows.h> /* Windows API */
#include <string.h>  /* strlen, strdup */
#include <stdio.h>   /* sprintf */
#include <io.h>      /* _unlink */
48 49 50
#ifdef __WATCOMC__
#define _unlink unlink
#endif
51 52 53 54 55 56 57 58

#ifndef _MAX_FNAME
#define _MAX_FNAME 4096
#endif
#ifndef _MAX_PATH
#define _MAX_PATH 4096
#endif

59 60 61 62 63
#ifdef _MSC_VER
#pragma warning (pop)
#pragma warning (disable: 4514)
#pragma warning (disable: 4706)
#endif
64

65 66 67 68
#if defined(__BORLANDC__)
# pragma warn -8060 /* Assignment inside if() condition.  */
#endif

69 70
/* There are pipes for the process pipeline's stdout and stderr.  */
#define KWSYSPE_PIPE_COUNT 2
71 72
#define KWSYSPE_PIPE_STDOUT 0
#define KWSYSPE_PIPE_STDERR 1
73 74

/* The maximum amount to read from a pipe at a time.  */
75
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
76

77
#define kwsysEncodedWriteArrayProcessFwd9x kwsys_ns(EncodedWriteArrayProcessFwd9x)
78 79 80

typedef LARGE_INTEGER kwsysProcessTime;

81 82 83 84 85
typedef struct kwsysProcessCreateInformation_s
{
  /* Windows child startup control data.  */
  STARTUPINFO StartupInfo;

86 87 88
  /* Special error reporting pipe for Win9x forwarding executable.  */
  HANDLE ErrorPipeRead;
  HANDLE ErrorPipeWrite;
89 90
} kwsysProcessCreateInformation;

91 92
/*--------------------------------------------------------------------------*/
typedef struct kwsysProcessPipeData_s kwsysProcessPipeData;
93 94 95
static DWORD WINAPI kwsysProcessPipeThreadRead(LPVOID ptd);
static void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp,
                                           kwsysProcessPipeData* td);
96
static DWORD WINAPI kwsysProcessPipeThreadWake(LPVOID ptd);
97 98
static void kwsysProcessPipeThreadWakePipe(kwsysProcess* cp,
                                           kwsysProcessPipeData* td);
99
static int kwsysProcessInitialize(kwsysProcess* cp);
100 101
static int kwsysProcessCreate(kwsysProcess* cp, int index,
                              kwsysProcessCreateInformation* si,
102 103
                              PHANDLE readEnd);
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
104
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
105
static int kwsysProcessSetupSharedPipe(DWORD nStdHandle, PHANDLE handle);
106
static void kwsysProcessCleanupHandle(PHANDLE h);
107
static void kwsysProcessCleanupHandleSafe(PHANDLE h, DWORD nStdHandle);
108
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
109
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
110 111 112 113 114
static int kwsysProcessComputeCommandLength(kwsysProcess* cp,
                                            char const* const* command);
static void kwsysProcessComputeCommandLine(kwsysProcess* cp,
                                           char const* const* command,
                                           char* cmd);
115 116
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
                                      kwsysProcessTime* timeoutTime);
117
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
118
                                      double* userTimeout,
119
                                      kwsysProcessTime* timeoutLength);
120
static kwsysProcessTime kwsysProcessTimeGetCurrent(void);
121 122 123 124 125 126
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);
127
static void kwsysProcessSetExitException(kwsysProcess* cp, int code);
128
static void kwsysProcessKillTree(int pid);
129
static void kwsysProcessDisablePipeThreads(kwsysProcess* cp);
Brad King's avatar
Brad King committed
130
extern kwsysEXPORT int kwsysEncodedWriteArrayProcessFwd9x(const char* fname);
131 132

/*--------------------------------------------------------------------------*/
133 134 135
/* A structure containing synchronization data for each thread.  */
typedef struct kwsysProcessPipeSync_s kwsysProcessPipeSync;
struct kwsysProcessPipeSync_s
136
{
137
  /* Handle to the thread.  */
138
  HANDLE Thread;
139

140
  /* Semaphore indicating to the thread that a process has started.  */
141
  HANDLE Ready;
142

143 144
  /* Semaphore indicating to the thread that it should begin work.  */
  HANDLE Go;
145

146
  /* Semaphore indicating thread has reset for another process.  */
147
  HANDLE Reset;
148
};
149

150 151 152 153 154 155 156 157
/*--------------------------------------------------------------------------*/
/* 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;
158

159 160
  /* Synchronization data for waking thread.  */
  kwsysProcessPipeSync Waker;
161

162 163 164 165 166
  /* Index of this pipe.  */
  int Index;

  /* The kwsysProcess instance owning this pipe.  */
  kwsysProcess* Process;
167

168
  /* ------------- Data managed per call to Execute ------------- */
169

170
  /* Buffer for data read in this pipe's thread.  */
171
  char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
172

173 174
  /* The length of the data stored in the buffer.  */
  DWORD DataLength;
175

176 177
  /* Whether the pipe has been closed.  */
  int Closed;
178

179 180
  /* Handle for the read end of this pipe. */
  HANDLE Read;
181

182 183
  /* Handle for the write end of this pipe. */
  HANDLE Write;
184
};
185 186 187 188 189 190

/*--------------------------------------------------------------------------*/
/* Structure containing data used to implement the child's execution.  */
struct kwsysProcess_s
{
  /* ------------- Data managed per instance of kwsysProcess ------------- */
191

192
  /* The status of the process structure.  */
193
  int State;
194

195 196 197 198 199 200
  /* The command lines to execute.  */
  char** Commands;
  int NumberOfCommands;

  /* The exit code of each command.  */
  DWORD* CommandExitCodes;
201

202 203
  /* The working directory for the child process.  */
  char* WorkingDirectory;
204

205 206 207 208 209 210
  /* Whether to create the child as a detached process.  */
  int OptionDetach;

  /* Whether the child was created as a detached process.  */
  int Detached;

211 212
  /* Whether to hide the child process's window.  */
  int HideWindow;
213

214 215 216
  /* Whether to treat command lines as verbatim.  */
  int Verbatim;

217 218
  /* On Win9x platforms, the path to the forwarding executable.  */
  char* Win9x;
219

220 221
  /* On Win9x platforms, the resume event for the forwarding executable.  */
  HANDLE Win9xResumeEvent;
222

223 224
  /* On Win9x platforms, the kill event for the forwarding executable.  */
  HANDLE Win9xKillEvent;
225

226 227
  /* Mutex to protect the shared index used by threads to report data.  */
  HANDLE SharedIndexMutex;
228

229 230
  /* Semaphore used by threads to signal data ready.  */
  HANDLE Full;
231

232 233
  /* Whether we are currently deleting this kwsysProcess instance.  */
  int Deleting;
234

235
  /* Data specific to each pipe and its thread.  */
236 237
  kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];

238 239 240 241 242
  /* Name of files to which stdin and stdout pipes are attached.  */
  char* PipeFileSTDIN;
  char* PipeFileSTDOUT;
  char* PipeFileSTDERR;

243 244 245 246 247
  /* Whether each pipe is shared with the parent process.  */
  int PipeSharedSTDIN;
  int PipeSharedSTDOUT;
  int PipeSharedSTDERR;

248 249 250
  /* Handle to automatically delete the Win9x forwarding executable.  */
  HANDLE Win9xHandle;

251
  /* ------------- Data managed per call to Execute ------------- */
252

253 254
  /* The exceptional behavior that terminated the process, if any.  */
  int ExitException;
255

256
  /* The process exit code.  */
257
  DWORD ExitCode;
258

259 260
  /* The process return code, if any.  */
  int ExitValue;
261

262 263
  /* Index of last pipe to report data, if any.  */
  int CurrentIndex;
264 265

  /* Index shared by threads to report data.  */
266
  int SharedIndex;
267

268 269
  /* The timeout length.  */
  double Timeout;
270

271 272
  /* Time at which the child started.  */
  kwsysProcessTime StartTime;
273

274 275
  /* Time at which the child will timeout.  Negative for no timeout.  */
  kwsysProcessTime TimeoutTime;
276

277 278
  /* Flag for whether the process was killed.  */
  int Killed;
279

280 281
  /* Flag for whether the timeout expired.  */
  int TimeoutExpired;
282

283 284
  /* Flag for whether the process has terminated.  */
  int Terminated;
285

286 287 288
  /* The number of pipes still open during execution and while waiting
     for pipes to close after process termination.  */
  int PipesLeft;
289

290
  /* Buffer for error messages (possibly from Win9x child).  */
291
  char ErrorMessage[KWSYSPE_PIPE_BUFFER_SIZE+1];
292

293 294 295
  /* Description for the ExitException.  */
  char ExitExceptionString[KWSYSPE_PIPE_BUFFER_SIZE+1];

296
  /* Windows process information data.  */
297 298 299 300 301
  PROCESS_INFORMATION* ProcessInformation;

  /* Data and process termination events for which to wait.  */
  PHANDLE ProcessEvents;
  int ProcessEventsLength;
302 303 304 305

  /* Real working directory of our own process.  */
  DWORD RealWorkingDirectoryLength;
  char* RealWorkingDirectory;
306 307 308
};

/*--------------------------------------------------------------------------*/
309
kwsysProcess* kwsysProcess_New(void)
310 311 312 313 314 315 316 317 318 319 320
{
  int i;

  /* Process control structure.  */
  kwsysProcess* cp;

  /* Path to Win9x forwarding executable.  */
  char* win9x = 0;

  /* Windows version number data.  */
  OSVERSIONINFO osv;
321

322 323
  /* Allocate a process control structure.  */
  cp = (kwsysProcess*)malloc(sizeof(kwsysProcess));
324 325 326 327 328
  if(!cp)
    {
    /* Could not allocate memory for the control structure.  */
    return 0;
    }
329
  ZeroMemory(cp, sizeof(*cp));
330

331 332 333
  /* Share stdin with the parent process by default.  */
  cp->PipeSharedSTDIN = 1;

334
  /* Set initial status.  */
335
  cp->State = kwsysProcess_State_Starting;
336

337 338 339 340 341
  /* Choose a method of running the child based on version of
     windows.  */
  ZeroMemory(&osv, sizeof(osv));
  osv.dwOSVersionInfoSize = sizeof(osv);
  GetVersionEx(&osv);
342
  if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
343 344 345 346 347
    {
    /* This is Win9x.  We need the console forwarding executable to
       work-around a Windows 9x bug.  */
    char fwdName[_MAX_FNAME+1] = "";
    char tempDir[_MAX_PATH+1] = "";
348

349
    /* We will try putting the executable in the system temp
350 351 352
       directory.  Note that the returned path already has a trailing
       slash.  */
    DWORD length = GetTempPath(_MAX_PATH+1, tempDir);
353

354 355
    /* Construct the executable name from the process id and kwsysProcess
       instance.  This should be unique.  */
356 357
    sprintf(fwdName, KWSYS_NAMESPACE_STRING "pew9xfwd_%u_%p.exe",
            GetCurrentProcessId(), cp);
358

359
    /* If we have a temp directory, use it.  */
360 361 362
    if(length > 0 && length <= _MAX_PATH)
      {
      /* Allocate a buffer to hold the forwarding executable path.  */
363
      size_t tdlen = strlen(tempDir);
364 365 366 367 368 369
      win9x = (char*)malloc(tdlen + strlen(fwdName) + 2);
      if(!win9x)
        {
        kwsysProcess_Delete(cp);
        return 0;
        }
370

371
      /* Construct the full path to the forwarding executable.  */
372
      sprintf(win9x, "%s%s", tempDir, fwdName);
373
      }
374

375 376 377 378 379 380 381 382 383 384 385
    /* If we found a place to put the forwarding executable, try to
       write it. */
    if(win9x)
      {
      if(!kwsysEncodedWriteArrayProcessFwd9x(win9x))
        {
        /* Failed to create forwarding executable.  Give up.  */
        free(win9x);
        kwsysProcess_Delete(cp);
        return 0;
        }
386 387 388 389 390 391 392 393 394 395 396 397 398

      /* Get a handle to the file that will delete it when closed.  */
      cp->Win9xHandle = CreateFile(win9x, GENERIC_READ, FILE_SHARE_READ, 0,
                                   OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
      if(cp->Win9xHandle == INVALID_HANDLE_VALUE)
        {
        /* We were not able to get a read handle for the forwarding
           executable.  It will not be deleted properly.  Give up.  */
        _unlink(win9x);
        free(win9x);
        kwsysProcess_Delete(cp);
        return 0;
        }
399 400 401 402 403 404 405 406
      }
    else
      {
      /* Failed to find a place to put forwarding executable.  */
      kwsysProcess_Delete(cp);
      return 0;
      }
    }
407

408
  /* Save the path to the forwarding executable.  */
409
  cp->Win9x = win9x;
410

411 412 413 414 415 416
  /* Initially no thread owns the mutex.  Initialize semaphore to 1.  */
  if(!(cp->SharedIndexMutex = CreateSemaphore(0, 1, 1, 0)))
    {
    kwsysProcess_Delete(cp);
    return 0;
    }
417

418 419 420 421 422 423 424 425 426 427 428 429 430
  /* Initially no data are available.  Initialize semaphore to 0.  */
  if(!(cp->Full = CreateSemaphore(0, 0, 1, 0)))
    {
    kwsysProcess_Delete(cp);
    return 0;
    }

  if(cp->Win9x)
    {
    SECURITY_ATTRIBUTES sa;
    ZeroMemory(&sa, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;
431 432 433 434 435 436 437 438 439 440 441

    /* Create an event to tell the forwarding executable to resume the
       child.  */
    if(!(cp->Win9xResumeEvent = CreateEvent(&sa, TRUE, 0, 0)))
      {
      kwsysProcess_Delete(cp);
      return 0;
      }

    /* Create an event to tell the forwarding executable to kill the
       child.  */
442 443 444 445 446 447
    if(!(cp->Win9xKillEvent = CreateEvent(&sa, TRUE, 0, 0)))
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
    }
448

449
  /* Create the thread to read each pipe.  */
450
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
451 452
    {
    DWORD dummy=0;
453

454 455
    /* Assign the thread its index.  */
    cp->Pipe[i].Index = i;
456

457 458
    /* Give the thread a pointer back to the kwsysProcess instance.  */
    cp->Pipe[i].Process = cp;
459

460 461
    /* No process is yet running.  Initialize semaphore to 0.  */
    if(!(cp->Pipe[i].Reader.Ready = CreateSemaphore(0, 0, 1, 0)))
462 463 464 465
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
466

467
    /* The pipe is not yet reset.  Initialize semaphore to 0.  */
468
    if(!(cp->Pipe[i].Reader.Reset = CreateSemaphore(0, 0, 1, 0)))
469 470 471 472
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
473

474
    /* The thread's buffer is initially empty.  Initialize semaphore to 1.  */
475
    if(!(cp->Pipe[i].Reader.Go = CreateSemaphore(0, 1, 1, 0)))
476 477 478 479
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
480

481 482 483 484 485 486
    /* 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)))
487 488 489 490
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
491

492 493
    /* No process is yet running.  Initialize semaphore to 0.  */
    if(!(cp->Pipe[i].Waker.Ready = CreateSemaphore(0, 0, 1, 0)))
494 495 496 497 498
      {
      kwsysProcess_Delete(cp);
      return 0;
      }

499 500
    /* The pipe is not yet reset.  Initialize semaphore to 0.  */
    if(!(cp->Pipe[i].Waker.Reset = CreateSemaphore(0, 0, 1, 0)))
501 502 503 504 505
      {
      kwsysProcess_Delete(cp);
      return 0;
      }

506 507
    /* The waker should not wake immediately.  Initialize semaphore to 0.  */
    if(!(cp->Pipe[i].Waker.Go = CreateSemaphore(0, 0, 1, 0)))
508 509 510 511 512 513 514 515
      {
      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.  */
516 517 518
    if(!(cp->Pipe[i].Waker.Thread = CreateThread(0, 1024,
                                                 kwsysProcessPipeThreadWake,
                                                 &cp->Pipe[i], 0, &dummy)))
519 520 521 522
      {
      kwsysProcess_Delete(cp);
      return 0;
      }
523
    }
524

525 526 527 528 529 530 531 532
  return cp;
}

/*--------------------------------------------------------------------------*/
void kwsysProcess_Delete(kwsysProcess* cp)
{
  int i;

533 534 535 536 537 538
  /* Make sure we have an instance.  */
  if(!cp)
    {
    return;
    }

539
  /* If the process is executing, wait for it to finish.  */
540
  if(cp->State == kwsysProcess_State_Executing)
541
    {
542 543 544 545 546 547 548 549
    if(cp->Detached)
      {
      kwsysProcess_Disown(cp);
      }
    else
      {
      kwsysProcess_WaitForExit(cp, 0);
      }
550
    }
551

552 553
  /* We are deleting the kwsysProcess instance.  */
  cp->Deleting = 1;
554

555
  /* Terminate each of the threads.  */
556
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
557
    {
558 559
    /* Terminate this reading thread.  */
    if(cp->Pipe[i].Reader.Thread)
560 561 562
      {
      /* Signal the thread we are ready for it.  It will terminate
         immediately since Deleting is set.  */
563
      ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
564

565
      /* Wait for the thread to exit.  */
566
      WaitForSingleObject(cp->Pipe[i].Reader.Thread, INFINITE);
567

568
      /* Close the handle to the thread. */
569
      kwsysProcessCleanupHandle(&cp->Pipe[i].Reader.Thread);
570
      }
571

572 573
    /* Terminate this waking thread.  */
    if(cp->Pipe[i].Waker.Thread)
574 575 576
      {
      /* Signal the thread we are ready for it.  It will terminate
         immediately since Deleting is set.  */
577
      ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
578 579

      /* Wait for the thread to exit.  */
580
      WaitForSingleObject(cp->Pipe[i].Waker.Thread, INFINITE);
581 582

      /* Close the handle to the thread. */
583
      kwsysProcessCleanupHandle(&cp->Pipe[i].Waker.Thread);
584 585
      }

586
    /* Cleanup the pipe's semaphores.  */
587 588 589 590 591 592
    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);
593 594
    }

595 596 597
  /* Close the shared semaphores.  */
  kwsysProcessCleanupHandle(&cp->SharedIndexMutex);
  kwsysProcessCleanupHandle(&cp->Full);
598

599
  /* Close the Win9x resume and kill event handles.  */
600 601
  if(cp->Win9x)
    {
602
    kwsysProcessCleanupHandle(&cp->Win9xResumeEvent);
603 604
    kwsysProcessCleanupHandle(&cp->Win9xKillEvent);
    }
605

606 607
  /* Free memory.  */
  kwsysProcess_SetCommand(cp, 0);
608
  kwsysProcess_SetWorkingDirectory(cp, 0);
609 610 611
  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
  kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
612 613 614 615
  if(cp->CommandExitCodes)
    {
    free(cp->CommandExitCodes);
    }
616 617
  if(cp->Win9x)
    {
618
    /* Close our handle to the forwarding executable file.  This will
619 620
       cause it to be deleted.  */
    kwsysProcessCleanupHandle(&cp->Win9xHandle);
621 622 623 624 625
    }
  free(cp);
}

/*--------------------------------------------------------------------------*/
626
int kwsysProcess_SetCommand(kwsysProcess* cp, char const* const* command)
627
{
628
  int i;
629 630 631 632
  if(!cp)
    {
    return 0;
    }
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
  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;
  char** newCommands;

  /* Make sure we have a command to add.  */
657
  if(!cp || !command || !*command)
658 659 660 661 662 663 664
    {
    return 0;
    }

  /* Allocate a new array for command pointers.  */
  newNumberOfCommands = cp->NumberOfCommands + 1;
  if(!(newCommands = (char**)malloc(sizeof(char*) * newNumberOfCommands)))
665
    {
666 667
    /* Out of memory.  */
    return 0;
668
    }
669 670 671 672 673 674 675 676 677 678

  /* Copy any existing commands into the new array.  */
  {
  int i;
  for(i=0; i < cp->NumberOfCommands; ++i)
    {
    newCommands[i] = cp->Commands[i];
    }
  }

679
  /* We need to construct a single string representing the command
680 681 682 683 684 685
     and its arguments.  We will surround each argument containing
     spaces with double-quotes.  Inside a double-quoted argument, we
     need to escape double-quotes and all backslashes before them.
     We also need to escape backslashes at the end of an argument
     because they come before the closing double-quote for the
     argument.  */
686 687
  {
  /* First determine the length of the final string.  */
688
  int length = kwsysProcessComputeCommandLength(cp, command);
689

690
  /* Allocate enough space for the command.  We do not need an extra
691 692
     byte for the terminating null because we allocated a space for
     the first argument that we will not use.  */
693 694 695 696 697 698 699
  newCommands[cp->NumberOfCommands] = (char*)malloc(length);
  if(!newCommands[cp->NumberOfCommands])
    {
    /* Out of memory.  */
    free(newCommands);
    return 0;
    }
700

701
  /* Construct the command line in the allocated buffer.  */
702 703
  kwsysProcessComputeCommandLine(cp, command,
                                 newCommands[cp->NumberOfCommands]);
704 705
  }

706 707 708 709 710
  /* Save the new array of commands.  */
  free(cp->Commands);
  cp->Commands = newCommands;
  cp->NumberOfCommands = newNumberOfCommands;
  return 1;
711 712 713 714 715
}

/*--------------------------------------------------------------------------*/
void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
{
716 717 718 719
  if(!cp)
    {
    return;
    }
720
  cp->Timeout = timeout;
721 722 723 724
  if(cp->Timeout < 0)
    {
    cp->Timeout = 0;
    }
725 726
}

727
/*--------------------------------------------------------------------------*/
728
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
729
{
730 731
  if(!cp)
    {
732
    return 0;
733
    }
734 735 736 737 738 739 740 741 742 743 744 745
  if(cp->WorkingDirectory)
    {
    free(cp->WorkingDirectory);
    cp->WorkingDirectory = 0;
    }
  if(dir && dir[0])
    {
    /* We must convert the working directory to a full path.  */
    DWORD length = GetFullPathName(dir, 0, 0, 0);
    if(length > 0)
      {
      cp->WorkingDirectory = (char*)malloc(length);
746 747 748 749
      if(!cp->WorkingDirectory)
        {
        return 0;
        }
750 751 752 753
      if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0))
        {
        free(cp->WorkingDirectory);
        cp->WorkingDirectory = 0;
754
        return 0;
755 756 757
        }
      }
    }
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
  return 1;
}

/*--------------------------------------------------------------------------*/
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* 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 = malloc(strlen(file)+1);
    if(!*pfile)
      {
      return 0;
      }
    strcpy(*pfile, file);
    }
790 791 792 793 794 795 796

  /* If we are redirecting the pipe, do not share it.  */
  if(*pfile)
    {
    kwsysProcess_SetPipeShared(cp, pipe, 0);
    }

797
  return 1;
798 799
}

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
/*--------------------------------------------------------------------------*/
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.  */
  if(shared)
    {
    kwsysProcess_SetPipeFile(cp, pipe, 0);
    }
}

823 824 825
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetOption(kwsysProcess* cp, int optionId)
{
826 827 828 829 830
  if(!cp)
    {
    return 0;
    }

831 832
  switch(optionId)
    {
833
    case kwsysProcess_Option_Detach: return cp->OptionDetach;
834
    case kwsysProcess_Option_HideWindow: return cp->HideWindow;
835
    case kwsysProcess_Option_Verbatim: return cp->Verbatim;
836 837
    default: return 0;
    }
838 839 840 841 842
}

/*--------------------------------------------------------------------------*/
void kwsysProcess_SetOption(kwsysProcess* cp, int optionId, int value)
{
843 844 845 846 847
  if(!cp)
    {
    return;
    }

848 849
  switch(optionId)
    {
850
    case kwsysProcess_Option_Detach: cp->OptionDetach = value; break;
851
    case kwsysProcess_Option_HideWindow: cp->HideWindow = value; break;
852
    case kwsysProcess_Option_Verbatim: cp->Verbatim = value; break;
853 854
    default: break;
    }
855 856
}

857 858 859
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetState(kwsysProcess* cp)
{
860
  return cp? cp->State : kwsysProcess_State_Error;
861 862
}

863 864 865
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitException(kwsysProcess* cp)
{
866
  return cp? cp->ExitException : kwsysProcess_Exception_Other;
867 868 869 870 871
}

/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitValue(kwsysProcess* cp)
{
872
  return cp? cp->ExitValue : -1;
873 874
}

875 876 877
/*--------------------------------------------------------------------------*/
int kwsysProcess_GetExitCode(kwsysProcess* cp)
{
878
  return cp? cp->ExitCode : 0;
879 880 881 882 883
}

/*--------------------------------------------------------------------------*/
const char* kwsysProcess_GetErrorString(kwsysProcess* cp)
{
884 885
  if(!cp)
    {
886
    return "Process management structure could not be allocated";
887 888
    }
  else if(cp->State == kwsysProcess_State_Error)
889 890 891
    {
    return cp->ErrorMessage;
    }
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
  return "Success";
}

/*--------------------------------------------------------------------------*/
const char* kwsysProcess_GetExceptionString(kwsysProcess* cp)
{
  if(!cp)
    {
    return "GetExceptionString called with NULL process management structure";
    }
  else if(cp->State == kwsysProcess_State_Exception)
    {
    return cp->ExitExceptionString;
    }
  return "No exception";
907 908 909 910 911
}

/*--------------------------------------------------------------------------*/
void kwsysProcess_Execute(kwsysProcess* cp)
{
912
  int i;
913

914 915
  /* Child startup control data.  */
  kwsysProcessCreateInformation si;
916

917
  /* Do not execute a second time.  */
918
  if(!cp || cp->State == kwsysProcess_State_Executing)
919 920 921
    {
    return;
    }
922 923 924

  /* Initialize the control structure for a new process.  */
  if(!kwsysProcessInitialize(cp))
925
    {
926 927
    strcpy(cp->ErrorMessage, "Out of memory");
    cp->State = kwsysProcess_State_Error;
928 929
    return;
    }
930

931 932 933 934 935 936 937 938 939 940 941 942 943 944
  /* 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(!GetCurrentDirectory(cp->RealWorkingDirectoryLength,
                            cp->RealWorkingDirectory))
      {
      kwsysProcessCleanup(cp, 1);
      return;
      }
    SetCurrentDirectory(cp->WorkingDirectory);
    }

945
  /* Reset the Win9x resume and kill events.  */
946 947
  if(cp->Win9x)
    {
948 949 950 951 952
    if(!ResetEvent(cp->Win9xResumeEvent))
      {
      kwsysProcessCleanup(cp, 1);
      return;
      }
953 954 955 956 957 958
    if(!ResetEvent(cp->Win9xKillEvent))
      {
      kwsysProcessCleanup(cp, 1);
      return;
      }
    }
959 960 961

  /* Initialize startup info data.  */
  ZeroMemory(&si, sizeof(si));
962
  si.StartupInfo.cb = sizeof(si.StartupInfo);
963

964
  /* Decide whether a child window should be shown.  */
965 966 967
  si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
  si.StartupInfo.wShowWindow =
    (unsigned short)(cp->HideWindow?SW_HIDE:SW_SHOWDEFAULT);
968

969
  /* Connect the child's output pipes to the threads.  */
970
  si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
971

972 973 974 975
  /* Create stderr pipe to be shared by all processes in the pipeline.
     Neither end is directly inherited.  */
  if(!CreatePipe(&cp->Pipe[KWSYSPE_PIPE_STDERR].Read,
                 &cp->Pipe[KWSYSPE_PIPE_STDERR].Write, 0, 0))
976
    {
977 978 979
    kwsysProcessCleanup(cp, 1);
    return;
    }
980

981 982 983 984 985 986 987 988 989 990
  /* Create an inherited duplicate of the write end, but do not
     close the non-inherited version.  We need to keep it open
     to use in waking up the pipe threads.  */
  if(!DuplicateHandle(GetCurrentProcess(), cp->Pipe[KWSYSPE_PIPE_STDERR].Write,
                      GetCurrentProcess(), &si.StartupInfo.hStdError,
                      0, TRUE, DUPLICATE_SAME_ACCESS))
    {
    kwsysProcessCleanup(cp, 1);
    kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
    return;
991
    }
992

993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
  /* Replace the stderr pipe with a file if requested.  In this case
     the pipe thread will still run but never report data.  */
  if(cp->PipeFileSTDERR)
    {
    if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError,
                                        cp->PipeFileSTDERR))
      {
      kwsysProcessCleanup(cp, 1);
      kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
      return;
      }
    }

1006 1007 1008 1009 1010
  /* Replace the stderr pipe with the parent process's if requested.
     In this case the pipe thread will still run but never report
     data.  */
  if(cp->PipeSharedSTDERR)
    {
1011 1012 1013 1014
    if(!kwsysProcessSetupSharedPipe(STD_ERROR_HANDLE,
                                    &si.StartupInfo.hStdError))
      {
      kwsysProcessCleanup(cp, 1);
1015 1016
      kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
                                    STD_ERROR_HANDLE);
1017 1018
      return;
      }
1019 1020
    }

1021 1022 1023 1024 1025 1026
  /* Create the pipeline of processes.  */
  {
  HANDLE readEnd = 0;
  for(i=0; i < cp->NumberOfCommands; ++i)
    {
    if(kwsysProcessCreate(cp, i, &si, &readEnd))
1027
      {
1028
      cp->ProcessEvents[i+1] = cp->ProcessInformation[i].hProcess;
1029
      }
1030
    else
1031 1032
      {
      kwsysProcessCleanup(cp, 1);
1033 1034 1035 1036

      /* Release resources that may have been allocated for this
         process before an error occurred.  */
      kwsysProcessCleanupHandle(&readEnd);
1037 1038 1039 1040 1041 1042
      kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdInput,
                                    STD_INPUT_HANDLE);
      kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdOutput,
                                    STD_OUTPUT_HANDLE);
      kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError,
                                    STD_ERROR_HANDLE);
1043 1044
      kwsysProcessCleanupHandle(&si.ErrorPipeRead);
      kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
1045 1046 1047
      return;
      }
    }
1048 1049

  /* Save a handle to the output pipe for the last process.  */
1050
  cp->Pipe[KWSYSPE_PIPE_STDOUT].Read = readEnd;
1051 1052
  }

1053
  /* Close the inherited handles to the stderr pipe shared by all
1054 1055 1056
     processes in the pipeline.  The stdout and stdin pipes are not
     shared among all children and are therefore closed by
     kwsysProcessCreate after each child is created.  */
1057
  kwsysProcessCleanupHandleSafe(&si.StartupInfo.hStdError, STD_ERROR_HANDLE);
1058

1059 1060 1061 1062 1063 1064 1065 1066
  /* Restore the working directory.  */
  if(cp->RealWorkingDirectory)
    {
    SetCurrentDirectory(cp->RealWorkingDirectory);
    free(cp->RealWorkingDirectory);
    cp->RealWorkingDirectory = 0;
    }

1067 1068 1069
  /* The timeout period starts now.  */
  cp->StartTime = kwsysProcessTimeGetCurrent();
  cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
1070

1071 1072
  /* All processes in the pipeline have been started in suspended
     mode.  Resume them all now.  */
1073 1074
  if(cp->Win9x)
    {
1075
    SetEvent(cp->Win9xResumeEvent);
1076 1077 1078
    }
  else
    {
1079 1080 1081 1082
    for(i=0; i < cp->NumberOfCommands; ++i)
      {
      ResumeThread(cp->ProcessInformation[i].hThread);
      }
1083
    }
1084

1085
  /* ---- It is no longer safe to call kwsysProcessCleanup. ----- */
1086
  /* Tell the pipe threads that a process has started.  */
1087
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1088
    {
1089 1090
    ReleaseSemaphore(cp->Pipe[i].Reader.Ready, 1, 0);
    ReleaseSemaphore(cp->Pipe[i].Waker.Ready, 1, 0);
1091
    }
1092 1093 1094 1095 1096 1097

  /* We don't care about the children's main threads.  */
  for(i=0; i < cp->NumberOfCommands; ++i)
    {
    kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hThread);
    }
1098

1099
  /* No pipe has reported data.  */
1100 1101
  cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
  cp->PipesLeft = KWSYSPE_PIPE_COUNT;
1102

1103
  /* The process has now started.  */
1104
  cp->State = kwsysProcess_State_Executing;
1105
  cp->Detached = cp->OptionDetach;
1106 1107
}

1108 1109 1110
/*--------------------------------------------------------------------------*/
void kwsysProcess_Disown(kwsysProcess* cp)
{
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
  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)
    {
1126 1127
    WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
    WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
1128 1129 1130 1131 1132 1133 1134
    }

  /* We will not wait for exit, so cleanup now.  */
  kwsysProcessCleanup(cp, 0);

  /* The process has been disowned.  */
  cp->State = kwsysProcess_State_Disowned;
1135 1136
}

1137 1138
/*--------------------------------------------------------------------------*/

1139
int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
1140 1141 1142 1143 1144 1145 1146 1147 1148
                             double* userTimeout)
{
  kwsysProcessTime userStartTime;
  kwsysProcessTime timeoutLength;
  kwsysProcessTime timeoutTime;
  DWORD timeout;
  int user;
  int done = 0;
  int expired = 0;
1149
  int pipeId = kwsysProcess_Pipe_None;
1150
  DWORD w;
1151

1152
  /* Make sure we are executing a process.  */
1153
  if(!cp || cp->State != kwsysProcess_State_Executing || cp->Killed ||
1154
     cp->TimeoutExpired)
1155
    {
1156
    return kwsysProcess_Pipe_None;
1157
    }
1158

1159
  /* Record the time at which user timeout period starts.  */
1160
  userStartTime = kwsysProcessTimeGetCurrent();
1161

1162 1163 1164
  /* Calculate the time at which a timeout will expire, and whether it
     is the user or process timeout.  */
  user = kwsysProcessGetTimeoutTime(cp, userTimeout, &timeoutTime);
1165

1166 1167 1168 1169 1170
  /* 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.  */
1171
    if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
1172
      {
1173
      ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
1174
      cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1175
      }
1176

1177
    /* Setup a timeout if required.  */
1178 1179
    if(kwsysProcessGetTimeoutLeft(&timeoutTime, user?userTimeout:0,
                                  &timeoutLength))
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
      {
      /* Timeout has already expired.  */
      expired = 1;
      break;
      }
    if(timeoutTime.QuadPart < 0)
      {
      timeout = INFINITE;
      }
    else
      {
      timeout = kwsysProcessTimeToDWORD(timeoutLength);
      }
1193

1194 1195 1196
    /* Wait for a pipe's thread to signal or a process to terminate.  */
    w = WaitForMultipleObjects(cp->ProcessEventsLength, cp->ProcessEvents,
                               0, timeout);
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
    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);
1209

1210 1211 1212
      /* Data are available or a pipe closed.  */
      if(cp->Pipe[cp->CurrentIndex].Closed)
        {
1213 1214 1215 1216
        /* 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);
1217 1218
        --cp->PipesLeft;
        }
1219
      else if(data && length)
1220
        {
1221
        /* Report this data.  */
1222 1223
        *data = cp->Pipe[cp->CurrentIndex].DataBuffer;
        *length = cp->Pipe[cp->CurrentIndex].DataLength;
1224 1225 1226 1227 1228 1229 1230
        switch(cp->CurrentIndex)
          {
          case KWSYSPE_PIPE_STDOUT:
            pipeId = kwsysProcess_Pipe_STDOUT; break;
          case KWSYSPE_PIPE_STDERR:
            pipeId = kwsysProcess_Pipe_STDERR; break;
          }
1231 1232 1233 1234 1235
        done = 1;
        }
      }
    else
      {
1236 1237
      /* A process has terminated.  */
      kwsysProcessDestroy(cp, w-WAIT_OBJECT_0);
1238 1239
      }
    }
1240

1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
  /* 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;
      }
    }
1254

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
  /* 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.  */
1267
      return kwsysProcess_Pipe_Timeout;
1268 1269 1270 1271 1272 1273 1274
      }
    else
      {
      /* The process timeout has expired.  Kill the child now.  */
      kwsysProcess_Kill(cp);
      cp->TimeoutExpired = 1;
      cp->Killed = 0;
1275
      return kwsysProcess_Pipe_None;
1276 1277 1278 1279
      }
    }
  else
    {
1280
    /* The children have terminated and no more data are available.  */
1281
    return kwsysProcess_Pipe_None;
1282 1283 1284 1285 1286 1287 1288
    }
}

/*--------------------------------------------------------------------------*/
int kwsysProcess_WaitForExit(kwsysProcess* cp, double* userTimeout)
{
  int i;
1289
  int pipe;
1290

1291
  /* Make sure we are executing a process.  */
1292
  if(!cp || cp->State != kwsysProcess_State_Executing)
1293 1294 1295
    {
    return 1;
    }
1296

1297
  /* Wait for the process to terminate.  Ignore all data.  */
1298
  while((pipe = kwsysProcess_WaitForData(cp, 0, 0, userTimeout)) > 0)
1299
    {
1300
    if(pipe == kwsysProcess_Pipe_Timeout)
1301 1302 1303 1304 1305 1306 1307
      {
      /* The user timeout has expired.  */
      return 0;
      }
    }

  /* When the last pipe closes in WaitForData, the loop terminates
1308
     without releasing the pipe's thread.  Release it now.  */
1309
  if(cp->CurrentIndex < KWSYSPE_PIPE_COUNT)
1310
    {
1311
    ReleaseSemaphore(cp->Pipe[cp->CurrentIndex].Reader.Go, 1, 0);
1312
    cp->CurrentIndex = KWSYSPE_PIPE_COUNT;
1313 1314 1315
    }

  /* Wait for all pipe threads to reset.  */
1316
  for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
1317
    {
1318 1319
    WaitForSingleObject(cp->Pipe[i].Reader.Reset, INFINITE);
    WaitForSingleObject(cp->Pipe[i].Waker.Reset, INFINITE);
1320
    }
1321

1322 1323 1324
  /* ---- It is now safe again to call kwsysProcessCleanup. ----- */
  /* Close all the pipes.  */
  kwsysProcessCleanup(cp, 0);
1325

1326 1327 1328 1329
  /* Determine the outcome.  */
  if(cp->Killed)
    {
    /* We killed the child.  */
1330
    cp->State = kwsysProcess_State_Killed;
1331 1332 1333 1334
    }
  else if(cp->TimeoutExpired)
    {
    /* The timeout expired.  */
1335
    cp->State = kwsysProcess_State_Expired;
1336
    }
1337
  else
1338
    {
1339 1340
    /* The children exited.  Report the outcome of the last process.  */
    cp->ExitCode = cp->CommandExitCodes[cp->NumberOfCommands-1];
1341
    if((cp->ExitCode & 0xF0000000) == 0xC0000000)
1342 1343
      {
      /* Child terminated due to exceptional behavior.  */
1344
      cp->State = kwsysProcess_State_Exception;
1345
      cp->ExitValue = 1;
1346
      kwsysProcessSetExitException(cp, cp->ExitCode);
1347 1348 1349
      }
    else
      {
1350
      /* Child exited without exception.  */
1351
      cp->State = kwsysProcess_State_Exited;