resolve merge conflicts of 9de005f0 to deqp-dev
[platform/upstream/VK-GL-CTS.git] / framework / delibs / deutil / deProcess.c
1 /*-------------------------------------------------------------------------
2  * drawElements Utility Library
3  * ----------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Process abstraction.
22  *//*--------------------------------------------------------------------*/
23
24 #include "deProcess.h"
25 #include "deMemory.h"
26 #include "deString.h"
27
28 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_SYMBIAN) || (DE_OS == DE_OS_QNX)
29
30 #include "deCommandLine.h"
31
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 typedef enum ProcessState_e
41 {
42         PROCESSSTATE_NOT_STARTED = 0,
43         PROCESSSTATE_RUNNING,
44         PROCESSSTATE_FINISHED,
45
46         PROCESSSTATE_LAST
47 } ProcessState;
48
49 struct deProcess_s
50 {
51         ProcessState    state;
52         int                             exitCode;
53         char*                   lastError;
54
55         pid_t                   pid;
56         deFile*                 standardIn;
57         deFile*                 standardOut;
58         deFile*                 standardErr;
59 };
60
61 static void die (int statusPipe, const char* message)
62 {
63         size_t  msgLen  = strlen(message);
64         int             res             = 0;
65
66         printf("Process launch failed: %s\n", message);
67         res = (int)write(statusPipe, message, msgLen+1);
68         DE_UNREF(res); /* No need to check result. */
69         exit(-1);
70 }
71
72 static void dieLastError (int statusPipe, const char* message)
73 {
74         char    msgBuf[256];
75         int             lastErr = errno;
76         deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
77         die(statusPipe, msgBuf);
78 }
79
80 DE_INLINE deBool beginsWithPath (const char* fileName, const char* pathPrefix)
81 {
82         size_t pathLen = strlen(pathPrefix);
83
84         /* Strip trailing / */
85         while (pathLen > 0 && pathPrefix[pathLen-1] == '/')
86                 pathLen -= 1;
87
88         return pathLen > 0 && deMemoryEqual(fileName, pathPrefix, pathLen) && fileName[pathLen] == '/';
89 }
90
91 static void stripLeadingPath (char* fileName, const char* pathPrefix)
92 {
93         size_t pathLen          = strlen(pathPrefix);
94         size_t fileNameLen      = strlen(fileName);
95
96         DE_ASSERT(beginsWithPath(fileName, pathPrefix));
97
98         /* Strip trailing / */
99         while (pathLen > 0 && pathPrefix[pathLen-1] == '/')
100                 pathLen -= 1;
101
102         DE_ASSERT(pathLen > 0);
103         DE_ASSERT(fileName[pathLen] == '/');
104
105         memmove(&fileName[0], &fileName[0]+pathLen+1, fileNameLen-pathLen);
106 }
107
108 /* Doesn't return on success. */
109 static void execProcess (const char* commandLine, const char* workingDirectory, int statusPipe)
110 {
111         deCommandLine*  cmdLine         = deCommandLine_parse(commandLine);
112         char**                  argList         = cmdLine ? (char**)deCalloc(sizeof(char*)*((size_t)cmdLine->numArgs+1)) : DE_NULL;
113
114         if (!cmdLine || !argList)
115                 die(statusPipe, "Command line parsing failed (out of memory)");
116
117         if (workingDirectory && chdir(workingDirectory) != 0)
118                 dieLastError(statusPipe, "chdir() failed");
119
120         {
121                 int argNdx;
122                 for (argNdx = 0; argNdx < cmdLine->numArgs; argNdx++)
123                         argList[argNdx] = cmdLine->args[argNdx];
124                 argList[argNdx] = DE_NULL; /* Terminate with 0. */
125         }
126
127         if (workingDirectory && beginsWithPath(argList[0], workingDirectory))
128                 stripLeadingPath(argList[0], workingDirectory);
129
130         execv(argList[0], argList);
131
132         /* Failed. */
133         dieLastError(statusPipe, "execv() failed");
134 }
135
136 deProcess* deProcess_create (void)
137 {
138         deProcess* process = (deProcess*)deCalloc(sizeof(deProcess));
139         if (!process)
140                 return DE_FALSE;
141
142         process->state = PROCESSSTATE_NOT_STARTED;
143
144         return process;
145 }
146
147 static void deProcess_cleanupHandles (deProcess* process)
148 {
149         if (process->standardIn)
150                 deFile_destroy(process->standardIn);
151
152         if (process->standardOut)
153                 deFile_destroy(process->standardOut);
154
155         if (process->standardErr)
156                 deFile_destroy(process->standardErr);
157
158         process->pid                    = 0;
159         process->standardIn             = DE_NULL;
160         process->standardOut    = DE_NULL;
161         process->standardErr    = DE_NULL;
162 }
163
164 void deProcess_destroy (deProcess* process)
165 {
166         /* Never leave child processes running. Otherwise we'll have zombies. */
167         if (deProcess_isRunning(process))
168         {
169                 deProcess_kill(process);
170                 deProcess_waitForFinish(process);
171         }
172
173         deProcess_cleanupHandles(process);
174         deFree(process->lastError);
175         deFree(process);
176 }
177
178 const char* deProcess_getLastError (const deProcess* process)
179 {
180         return process->lastError ? process->lastError : "No error";
181 }
182
183 int deProcess_getExitCode (const deProcess* process)
184 {
185         return process->exitCode;
186 }
187
188 static deBool deProcess_setError (deProcess* process, const char* error)
189 {
190         if (process->lastError)
191         {
192                 deFree(process->lastError);
193                 process->lastError = DE_NULL;
194         }
195
196         process->lastError = deStrdup(error);
197         return process->lastError != DE_NULL;
198 }
199
200 static deBool deProcess_setErrorFromErrno (deProcess* process, const char* message)
201 {
202         char    msgBuf[256];
203         int             lastErr         = errno;
204         deSprintf(msgBuf, sizeof(msgBuf), "%s, error %d: %s", message, lastErr, strerror(lastErr));
205         return deProcess_setError(process, message);
206 }
207
208 static void closePipe (int p[2])
209 {
210         if (p[0] >= 0)
211                 close(p[0]);
212         if (p[1] >= 0)
213                 close(p[1]);
214 }
215
216 deBool deProcess_start (deProcess* process, const char* commandLine, const char* workingDirectory)
217 {
218         pid_t           pid                             = 0;
219         int                     pipeIn[2]               = { -1, -1 };
220         int                     pipeOut[2]              = { -1, -1 };
221         int                     pipeErr[2]              = { -1, -1 };
222         int                     statusPipe[2]   = { -1, -1 };
223
224         if (process->state == PROCESSSTATE_RUNNING)
225         {
226                 deProcess_setError(process, "Process already running");
227                 return DE_FALSE;
228         }
229         else if (process->state == PROCESSSTATE_FINISHED)
230         {
231                 deProcess_cleanupHandles(process);
232                 process->state = PROCESSSTATE_NOT_STARTED;
233         }
234
235         if (pipe(pipeIn) < 0 || pipe(pipeOut) < 0 || pipe(pipeErr) < 0 || pipe(statusPipe) < 0)
236         {
237                 deProcess_setErrorFromErrno(process, "pipe() failed");
238
239                 closePipe(pipeIn);
240                 closePipe(pipeOut);
241                 closePipe(pipeErr);
242                 closePipe(statusPipe);
243
244                 return DE_FALSE;
245         }
246
247         pid = fork();
248
249         if (pid < 0)
250         {
251                 deProcess_setErrorFromErrno(process, "fork() failed");
252
253                 closePipe(pipeIn);
254                 closePipe(pipeOut);
255                 closePipe(pipeErr);
256                 closePipe(statusPipe);
257
258                 return DE_FALSE;
259         }
260
261         if (pid == 0)
262         {
263                 /* Child process. */
264
265                 /* Close unused endpoints. */
266                 close(pipeIn[1]);
267                 close(pipeOut[0]);
268                 close(pipeErr[0]);
269                 close(statusPipe[0]);
270
271                 /* Set status pipe to close on exec(). That way parent will know that exec() succeeded. */
272                 if (fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC) != 0)
273                         dieLastError(statusPipe[1], "Failed to set FD_CLOEXEC");
274
275                 /* Map stdin. */
276                 if (pipeIn[0] != STDIN_FILENO &&
277                         dup2(pipeIn[0], STDIN_FILENO) != STDIN_FILENO)
278                         dieLastError(statusPipe[1], "dup2() failed");
279                 close(pipeIn[0]);
280
281                 /* Stdout. */
282                 if (pipeOut[1] != STDOUT_FILENO &&
283                         dup2(pipeOut[1], STDOUT_FILENO) != STDOUT_FILENO)
284                         dieLastError(statusPipe[1], "dup2() failed");
285                 close(pipeOut[1]);
286
287                 /* Stderr. */
288                 if (pipeErr[1] != STDERR_FILENO &&
289                         dup2(pipeErr[1], STDERR_FILENO) != STDERR_FILENO)
290                         dieLastError(statusPipe[1], "dup2() failed");
291                 close(pipeErr[1]);
292
293                 /* Doesn't return. */
294                 execProcess(commandLine, workingDirectory, statusPipe[1]);
295         }
296         else
297         {
298                 /* Parent process. */
299
300                 /* Check status. */
301                 {
302                         char    errBuf[256];
303                         ssize_t result = 0;
304
305                         close(statusPipe[1]);
306                         while ((result = read(statusPipe[0], errBuf, 1)) == -1)
307                                 if (errno != EAGAIN && errno != EINTR) break;
308
309                         if (result > 0)
310                         {
311                                 int procStatus = 0;
312
313                                 /* Read full error msg. */
314                                 int errPos = 1;
315                                 while (errPos < DE_LENGTH_OF_ARRAY(errBuf))
316                                 {
317                                         result = read(statusPipe[0], errBuf+errPos, 1);
318                                         if (result == -1)
319                                                 break; /* Done. */
320
321                                         errPos += 1;
322                                 }
323
324                                 /* Make sure str is null-terminated. */
325                                 errBuf[errPos] = 0;
326
327                                 /* Close handles. */
328                                 close(statusPipe[0]);
329                                 closePipe(pipeIn);
330                                 closePipe(pipeOut);
331                                 closePipe(pipeErr);
332
333                                 /* Run waitpid to clean up zombie. */
334                                 waitpid(pid, &procStatus, 0);
335
336                                 deProcess_setError(process, errBuf);
337
338                                 return DE_FALSE;
339                         }
340
341                         /* Status pipe is not needed. */
342                         close(statusPipe[0]);
343                 }
344
345                 /* Set running state. */
346                 process->pid            = pid;
347                 process->state          = PROCESSSTATE_RUNNING;
348
349                 /* Stdin, stdout. */
350                 close(pipeIn[0]);
351                 close(pipeOut[1]);
352                 close(pipeErr[1]);
353
354                 process->standardIn             = deFile_createFromHandle((deUintptr)pipeIn[1]);
355                 process->standardOut    = deFile_createFromHandle((deUintptr)pipeOut[0]);
356                 process->standardErr    = deFile_createFromHandle((deUintptr)pipeErr[0]);
357
358                 if (!process->standardIn)
359                         close(pipeIn[1]);
360
361                 if (!process->standardOut)
362                         close(pipeOut[0]);
363
364                 if (!process->standardErr)
365                         close(pipeErr[0]);
366         }
367
368         return DE_TRUE;
369 }
370
371 deBool deProcess_isRunning (deProcess* process)
372 {
373         if (process->state == PROCESSSTATE_RUNNING)
374         {
375                 int status = 0;
376
377                 if (waitpid(process->pid, &status, WNOHANG) == 0)
378                         return DE_TRUE; /* No status available. */
379
380                 if (WIFEXITED(status) || WIFSIGNALED(status))
381                 {
382                         /* Child has finished. */
383                         process->state = PROCESSSTATE_FINISHED;
384                         return DE_FALSE;
385                 }
386                 else
387                         return DE_TRUE;
388         }
389         else
390                 return DE_FALSE;
391 }
392
393 deBool deProcess_waitForFinish (deProcess* process)
394 {
395         int             status = 0;
396         pid_t   waitResult;
397
398         if (process->state != PROCESSSTATE_RUNNING)
399         {
400                 deProcess_setError(process, "Process is not running");
401                 return DE_FALSE;
402         }
403
404         /* \note [pyry] HACK, apparently needed by some versions of OS X. */
405         while ((waitResult = waitpid(process->pid, &status, 0)) != process->pid)
406                 if (errno != ENOENT) break;
407
408         if (waitResult != process->pid)
409         {
410                 deProcess_setErrorFromErrno(process, "waitpid() failed");
411                 return DE_FALSE; /* waitpid() failed. */
412         }
413
414         if (!WIFEXITED(status) && !WIFSIGNALED(status))
415         {
416                 deProcess_setErrorFromErrno(process, "waitpid() failed");
417                 return DE_FALSE; /* Something strange happened. */
418         }
419
420         process->exitCode       = WEXITSTATUS(status);
421         process->state          = PROCESSSTATE_FINISHED;
422         return DE_TRUE;
423 }
424
425 static deBool deProcess_sendSignal (deProcess* process, int sigNum)
426 {
427         if (process->state != PROCESSSTATE_RUNNING)
428         {
429                 deProcess_setError(process, "Process is not running");
430                 return DE_FALSE;
431         }
432
433         if (kill(process->pid, sigNum) == 0)
434                 return DE_TRUE;
435         else
436         {
437                 deProcess_setErrorFromErrno(process, "kill() failed");
438                 return DE_FALSE;
439         }
440 }
441
442 deBool deProcess_terminate (deProcess* process)
443 {
444         return deProcess_sendSignal(process, SIGTERM);
445 }
446
447 deBool deProcess_kill (deProcess* process)
448 {
449         return deProcess_sendSignal(process, SIGKILL);
450 }
451
452 deFile* deProcess_getStdIn (deProcess* process)
453 {
454         return process->standardIn;
455 }
456
457 deFile* deProcess_getStdOut (deProcess* process)
458 {
459         return process->standardOut;
460 }
461
462 deFile* deProcess_getStdErr (deProcess* process)
463 {
464         return process->standardErr;
465 }
466
467 deBool deProcess_closeStdIn (deProcess* process)
468 {
469         if (process->standardIn)
470         {
471                 deFile_destroy(process->standardIn);
472                 process->standardIn     = DE_NULL;
473                 return DE_TRUE;
474         }
475         else
476                 return DE_FALSE;
477 }
478
479 deBool deProcess_closeStdOut (deProcess* process)
480 {
481         if (process->standardOut)
482         {
483                 deFile_destroy(process->standardOut);
484                 process->standardOut = DE_NULL;
485                 return DE_TRUE;
486         }
487         else
488                 return DE_FALSE;
489 }
490
491 deBool deProcess_closeStdErr (deProcess* process)
492 {
493         if (process->standardErr)
494         {
495                 deFile_destroy(process->standardErr);
496                 process->standardErr = DE_NULL;
497                 return DE_TRUE;
498         }
499         else
500                 return DE_FALSE;
501 }
502
503 #elif (DE_OS == DE_OS_WIN32)
504
505 #define VC_EXTRALEAN
506 #define WIN32_LEAN_AND_MEAN
507 #include <windows.h>
508 #include <strsafe.h>
509
510 typedef enum ProcessState_e
511 {
512         PROCESSSTATE_NOT_STARTED = 0,
513         PROCESSSTATE_RUNNING,
514         PROCESSSTATE_FINISHED,
515
516         PROCESSSTATE_LAST
517 } ProcessState;
518
519 struct deProcess_s
520 {
521         ProcessState                    state;
522         char*                                   lastError;
523         int                                             exitCode;
524
525         PROCESS_INFORMATION             procInfo;
526         deFile*                                 standardIn;
527         deFile*                                 standardOut;
528         deFile*                                 standardErr;
529 };
530
531 static deBool deProcess_setError (deProcess* process, const char* error)
532 {
533         if (process->lastError)
534         {
535                 deFree(process->lastError);
536                 process->lastError = DE_NULL;
537         }
538
539         process->lastError = deStrdup(error);
540         return process->lastError != DE_NULL;
541 }
542
543 static deBool deProcess_setErrorFromWin32 (deProcess* process, const char* msg)
544 {
545         DWORD           error   = GetLastError();
546         LPSTR           msgBuf;
547         char            errBuf[256];
548
549 #if defined(UNICODE)
550 #       error Unicode not supported.
551 #endif
552
553         if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
554                                           NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&msgBuf, 0, DE_NULL) > 0)
555         {
556                 deSprintf(errBuf, sizeof(errBuf), "%s, error %d: %s", msg, error, msgBuf);
557                 LocalFree(msgBuf);
558                 return deProcess_setError(process, errBuf);
559         }
560         else
561         {
562                 /* Failed to get error str. */
563                 deSprintf(errBuf, sizeof(errBuf), "%s, error %d", msg, error);
564                 return deProcess_setError(process, errBuf);
565         }
566 }
567
568 deProcess* deProcess_create (void)
569 {
570         deProcess* process = (deProcess*)deCalloc(sizeof(deProcess));
571         if (!process)
572                 return DE_NULL;
573
574         process->state = PROCESSSTATE_NOT_STARTED;
575
576         return process;
577 }
578
579 void deProcess_cleanupHandles (deProcess* process)
580 {
581         DE_ASSERT(!deProcess_isRunning(process));
582
583         if (process->standardErr)
584                 deFile_destroy(process->standardErr);
585
586         if (process->standardOut)
587                 deFile_destroy(process->standardOut);
588
589         if (process->standardIn)
590                 deFile_destroy(process->standardIn);
591
592         if (process->procInfo.hProcess)
593                 CloseHandle(process->procInfo.hProcess);
594
595         if (process->procInfo.hThread)
596                 CloseHandle(process->procInfo.hThread);
597
598         process->standardErr            = DE_NULL;
599         process->standardOut            = DE_NULL;
600         process->standardIn                     = DE_NULL;
601         process->procInfo.hProcess      = DE_NULL;
602         process->procInfo.hThread       = DE_NULL;
603 }
604
605 void deProcess_destroy (deProcess* process)
606 {
607         if (deProcess_isRunning(process))
608         {
609                 deProcess_kill(process);
610                 deProcess_waitForFinish(process);
611         }
612
613         deProcess_cleanupHandles(process);
614         deFree(process->lastError);
615         deFree(process);
616 }
617
618 const char* deProcess_getLastError (const deProcess* process)
619 {
620         return process->lastError ? process->lastError : "No error";
621 }
622
623 int deProcess_getExitCode (const deProcess* process)
624 {
625         return process->exitCode;
626 }
627
628 deBool deProcess_start (deProcess* process, const char* commandLine, const char* workingDirectory)
629 {
630         SECURITY_ATTRIBUTES     securityAttr;
631         STARTUPINFO                     startInfo;
632
633         /* Pipes. */
634         HANDLE          stdInRead       = DE_NULL;
635         HANDLE          stdInWrite      = DE_NULL;
636         HANDLE          stdOutRead      = DE_NULL;
637         HANDLE          stdOutWrite     = DE_NULL;
638         HANDLE          stdErrRead      = DE_NULL;
639         HANDLE          stdErrWrite     = DE_NULL;
640
641         if (process->state == PROCESSSTATE_RUNNING)
642         {
643                 deProcess_setError(process, "Process already running");
644                 return DE_FALSE;
645         }
646         else if (process->state == PROCESSSTATE_FINISHED)
647         {
648                 /* Process finished, clean up old cruft. */
649                 deProcess_cleanupHandles(process);
650                 process->state = PROCESSSTATE_NOT_STARTED;
651         }
652
653         deMemset(&startInfo, 0, sizeof(startInfo));
654         deMemset(&securityAttr, 0, sizeof(securityAttr));
655
656         /* Security attributes for inheriting handle. */
657         securityAttr.nLength                            = sizeof(SECURITY_ATTRIBUTES);
658         securityAttr.bInheritHandle                     = TRUE;
659         securityAttr.lpSecurityDescriptor       = DE_NULL;
660
661         /* Create pipes. \todo [2011-10-03 pyry] Clean up handles on error! */
662         if (!CreatePipe(&stdInRead, &stdInWrite, &securityAttr, 0) ||
663                 !SetHandleInformation(stdInWrite, HANDLE_FLAG_INHERIT, 0))
664         {
665                 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
666                 CloseHandle(stdInRead);
667                 CloseHandle(stdInWrite);
668                 return DE_FALSE;
669         }
670
671         if (!CreatePipe(&stdOutRead, &stdOutWrite, &securityAttr, 0) ||
672                 !SetHandleInformation(stdOutRead, HANDLE_FLAG_INHERIT, 0))
673         {
674                 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
675                 CloseHandle(stdInRead);
676                 CloseHandle(stdInWrite);
677                 CloseHandle(stdOutRead);
678                 CloseHandle(stdOutWrite);
679                 return DE_FALSE;
680         }
681
682         if (!CreatePipe(&stdErrRead, &stdErrWrite, &securityAttr, 0) ||
683                 !SetHandleInformation(stdErrRead, HANDLE_FLAG_INHERIT, 0))
684         {
685                 deProcess_setErrorFromWin32(process, "CreatePipe() failed");
686                 CloseHandle(stdInRead);
687                 CloseHandle(stdInWrite);
688                 CloseHandle(stdOutRead);
689                 CloseHandle(stdOutWrite);
690                 CloseHandle(stdErrRead);
691                 CloseHandle(stdErrWrite);
692                 return DE_FALSE;
693         }
694
695         /* Setup startup info. */
696         startInfo.cb = sizeof(startInfo);
697         startInfo.hStdError              = stdErrWrite;
698         startInfo.hStdOutput     = stdOutWrite;
699         startInfo.hStdInput              = stdInRead;
700         startInfo.dwFlags               |= STARTF_USESTDHANDLES;
701
702         if (!CreateProcess(DE_NULL, (LPTSTR)commandLine, DE_NULL, DE_NULL, TRUE /* inherit handles */, 0, DE_NULL, workingDirectory, &startInfo, &process->procInfo))
703         {
704                 /* Store error info. */
705                 deProcess_setErrorFromWin32(process, "CreateProcess() failed");
706
707                 /* Close all handles. */
708                 CloseHandle(stdInRead);
709                 CloseHandle(stdInWrite);
710                 CloseHandle(stdOutRead);
711                 CloseHandle(stdOutWrite);
712                 CloseHandle(stdErrRead);
713                 CloseHandle(stdErrWrite);
714
715                 return DE_FALSE;
716         }
717
718         process->state = PROCESSSTATE_RUNNING;
719
720         /* Close our ends of handles.*/
721         CloseHandle(stdErrWrite);
722         CloseHandle(stdOutWrite);
723         CloseHandle(stdInRead);
724
725         /* Construct stdio file objects \note May fail, not detected. */
726         process->standardIn             = deFile_createFromHandle((deUintptr)stdInWrite);
727         process->standardOut    = deFile_createFromHandle((deUintptr)stdOutRead);
728         process->standardErr    = deFile_createFromHandle((deUintptr)stdErrRead);
729
730         return DE_TRUE;
731 }
732
733 deBool deProcess_isRunning (deProcess* process)
734 {
735         if (process->state == PROCESSSTATE_RUNNING)
736         {
737                 int exitCode;
738                 BOOL result = GetExitCodeProcess(process->procInfo.hProcess, (LPDWORD)&exitCode);
739
740                 if (result != TRUE)
741                 {
742                         deProcess_setErrorFromWin32(process, "GetExitCodeProcess() failed");
743                         return DE_FALSE;
744                 }
745
746                 if (exitCode == STILL_ACTIVE)
747                         return DE_TRUE;
748                 else
749                 {
750                         /* Done. */
751                         process->exitCode       = exitCode;
752                         process->state          = PROCESSSTATE_FINISHED;
753                         return DE_FALSE;
754                 }
755         }
756         else
757                 return DE_FALSE;
758 }
759
760 deBool deProcess_waitForFinish (deProcess* process)
761 {
762         if (process->state == PROCESSSTATE_RUNNING)
763         {
764                 if (WaitForSingleObject(process->procInfo.hProcess, INFINITE) != WAIT_OBJECT_0)
765                 {
766                         deProcess_setErrorFromWin32(process, "WaitForSingleObject() failed");
767                         return DE_FALSE;
768                 }
769                 return !deProcess_isRunning(process);
770         }
771         else
772         {
773                 deProcess_setError(process, "Process is not running");
774                 return DE_FALSE;
775         }
776 }
777
778 static deBool stopProcess (deProcess* process, deBool kill)
779 {
780         if (process->state == PROCESSSTATE_RUNNING)
781         {
782                 if (!TerminateProcess(process->procInfo.hProcess, kill ? -1 : 0))
783                 {
784                         deProcess_setErrorFromWin32(process, "TerminateProcess() failed");
785                         return DE_FALSE;
786                 }
787                 else
788                         return DE_TRUE;
789         }
790         else
791         {
792                 deProcess_setError(process, "Process is not running");
793                 return DE_FALSE;
794         }
795 }
796
797 deBool deProcess_terminate (deProcess* process)
798 {
799         return stopProcess(process, DE_FALSE);
800 }
801
802 deBool deProcess_kill (deProcess* process)
803 {
804         return stopProcess(process, DE_TRUE);
805 }
806
807 deFile* deProcess_getStdIn (deProcess* process)
808 {
809         return process->standardIn;
810 }
811
812 deFile* deProcess_getStdOut (deProcess* process)
813 {
814         return process->standardOut;
815 }
816
817 deFile* deProcess_getStdErr (deProcess* process)
818 {
819         return process->standardErr;
820 }
821
822 deBool deProcess_closeStdIn (deProcess* process)
823 {
824         if (process->standardIn)
825         {
826                 deFile_destroy(process->standardIn);
827                 process->standardIn     = DE_NULL;
828                 return DE_TRUE;
829         }
830         else
831                 return DE_FALSE;
832 }
833
834 deBool deProcess_closeStdOut (deProcess* process)
835 {
836         if (process->standardOut)
837         {
838                 deFile_destroy(process->standardOut);
839                 process->standardOut = DE_NULL;
840                 return DE_TRUE;
841         }
842         else
843                 return DE_FALSE;
844 }
845
846 deBool deProcess_closeStdErr (deProcess* process)
847 {
848         if (process->standardErr)
849         {
850                 deFile_destroy(process->standardErr);
851                 process->standardErr = DE_NULL;
852                 return DE_TRUE;
853         }
854         else
855                 return DE_FALSE;
856 }
857
858 #else
859 #       error Implement deProcess for your OS.
860 #endif