original patch from Mantis 1614
[oweals/gnunet.git] / src / util / os_priority.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file util/os_priority.c
23  * @brief Methods to set process priority
24  * @author Nils Durner
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_os_lib.h"
30 #include "disk.h"
31
32 struct _GNUNET_OS_Process
33 {
34   pid_t pid;
35 #if WINDOWS
36   HANDLE handle;
37 #endif
38 };
39
40 static GNUNET_OS_Process current_process;
41
42 GNUNET_OS_Process *
43 GNUNET_OS_process_alloc ()
44 {
45   GNUNET_OS_Process *ret = GNUNET_malloc (sizeof (GNUNET_OS_Process));
46   ret->pid = 0;
47 #if WINDOWS
48   ret->handle = NULL;
49 #endif
50   return ret;
51 }
52
53 /**
54  * Get process structure for current process
55  *
56  * The pointer it returns points to static memory location and must not be
57  * deallocated/closed
58  *
59  * @return pointer to the process sturcutre for this process
60  */
61 GNUNET_OS_Process *
62 GNUNET_OS_process_current ()
63 {
64 #if WINDOWS
65   current_process.pid = GetCurrentProcessId ();
66   current_process.handle = GetCurrentProcess ();
67 #else
68   current_process.pid = 0;
69 #endif
70   return &current_process;
71 }
72
73 int
74 GNUNET_OS_process_kill (GNUNET_OS_Process *proc, int sig)
75 {
76 #if WINDOWS
77   if (sig == SIGKILL || sig == SIGTERM)
78   {
79     HANDLE h = GNUNET_OS_process_get_handle (proc);
80     if (NULL == h)
81     {
82       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", GNUNET_OS_process_get_pid (proc), h);
83       return -1;
84     }
85     if (!TerminateProcess (h, 0))
86     {
87       SetErrnoFromWinError (GetLastError ());
88       return -1;
89     }
90     else
91       return 0;
92   }
93   errno = EINVAL;
94   return -1;
95 #else
96   return kill (GNUNET_OS_process_get_pid (proc), sig);
97 #endif
98 }
99
100 pid_t
101 GNUNET_OS_process_get_pid (GNUNET_OS_Process *proc)
102 {
103   return proc->pid;
104 }
105
106 void
107 GNUNET_OS_process_set_pid (GNUNET_OS_Process *proc, pid_t pid)
108 {
109   proc->pid = pid;
110 }
111
112 #if WINDOWS
113 HANDLE
114 GNUNET_OS_process_get_handle (GNUNET_OS_Process *proc)
115 {
116   return proc->handle;
117 }
118
119 void
120 GNUNET_OS_process_set_handle(GNUNET_OS_Process *proc, HANDLE handle)
121 {
122   if (proc->handle != NULL)
123     CloseHandle (proc->handle);
124   proc->handle = handle;
125 }
126 #endif
127
128 void
129 GNUNET_OS_process_close (GNUNET_OS_Process *proc)
130 {
131 #if WINDOWS
132   if (proc->handle != NULL)
133     CloseHandle (proc->handle);
134 #endif  
135   GNUNET_free (proc);
136 }
137
138 #if WINDOWS
139 #include "gnunet_signal_lib.h"
140
141 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
142
143 /**
144  * @brief Waits for a process to terminate and invokes the SIGCHLD handler
145  * @param proc pointer to process structure
146  */
147 static DWORD WINAPI
148 ChildWaitThread (void *arg)
149 {
150   GNUNET_OS_Process *proc = (GNUNET_OS_Process *) arg;
151   WaitForSingleObject (proc->handle, INFINITE);
152
153   if (w32_sigchld_handler)
154     w32_sigchld_handler ();
155
156   return 0;
157 }
158 #endif
159
160 /**
161  * Set process priority
162  *
163  * @param proc pointer to process structure
164  * @param prio priority value
165  * @return GNUNET_OK on success, GNUNET_SYSERR on error
166  */
167 int
168 GNUNET_OS_set_process_priority (GNUNET_OS_Process *proc,
169                                 enum GNUNET_SCHEDULER_Priority prio)
170 {
171   int rprio;
172   pid_t pid;
173
174   GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
175   if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
176     return GNUNET_OK;
177
178   /* convert to MINGW/Unix values */
179   switch (prio)
180     {
181     case GNUNET_SCHEDULER_PRIORITY_UI:
182     case GNUNET_SCHEDULER_PRIORITY_URGENT:
183 #ifdef MINGW
184       rprio = HIGH_PRIORITY_CLASS;
185 #else
186       rprio = 0;
187 #endif
188       break;
189
190     case GNUNET_SCHEDULER_PRIORITY_HIGH:
191 #ifdef MINGW
192       rprio = ABOVE_NORMAL_PRIORITY_CLASS;
193 #else
194       rprio = 5;
195 #endif
196       break;
197
198     case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
199 #ifdef MINGW
200       rprio = NORMAL_PRIORITY_CLASS;
201 #else
202       rprio = 7;
203 #endif
204       break;
205
206     case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
207 #ifdef MINGW
208       rprio = BELOW_NORMAL_PRIORITY_CLASS;
209 #else
210       rprio = 10;
211 #endif
212       break;
213
214     case GNUNET_SCHEDULER_PRIORITY_IDLE:
215 #ifdef MINGW
216       rprio = IDLE_PRIORITY_CLASS;
217 #else
218       rprio = 19;
219 #endif
220       break;
221     default:
222       GNUNET_assert (0);
223       return GNUNET_SYSERR;
224     }
225
226   pid = GNUNET_OS_process_get_pid (proc);
227
228   /* Set process priority */
229 #ifdef MINGW
230   {
231     HANDLE h = GNUNET_OS_process_get_handle (proc);
232     GNUNET_assert (h != NULL);
233     SetPriorityClass (h, rprio);
234   }
235 #elif LINUX 
236   if ( (0 == pid) ||
237        (pid == getpid () ) )
238     {
239       int have = nice (0);
240       int delta = rprio - have;
241       errno = 0;
242       if ( (delta != 0) &&
243            (rprio == nice (delta)) && 
244            (errno != 0) )
245         {
246           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING |
247                                GNUNET_ERROR_TYPE_BULK, "nice");
248           return GNUNET_SYSERR;
249         }
250     }
251   else
252     {
253       if (0 != setpriority (PRIO_PROCESS, pid, rprio))
254
255         {
256           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING |
257                                GNUNET_ERROR_TYPE_BULK, "setpriority");
258           return GNUNET_SYSERR;
259         }
260     }
261 #else
262   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
263               "Priority management not availabe for this platform\n");
264 #endif
265   return GNUNET_OK;
266 }
267
268 /**
269  * Start a process.
270  *
271  * @param pipe_stdin pipe to use to send input to child process (or NULL)
272  * @param pipe_stdout pipe to use to get output from child process (or NULL)
273  * @param filename name of the binary
274  * @param ... NULL-terminated list of arguments to the process
275  * @return pointer to process structure of the new process, NULL on error
276  */
277 GNUNET_OS_Process *
278 GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin, 
279                          struct GNUNET_DISK_PipeHandle *pipe_stdout,
280                          const char *filename, ...)
281 {
282   va_list ap;
283
284 #ifndef MINGW
285   pid_t ret;
286   GNUNET_OS_Process *gnunet_proc = NULL;
287   char **argv;
288   int argc;
289   int fd_stdout_write;
290   int fd_stdout_read;
291   int fd_stdin_read;
292   int fd_stdin_write;
293
294   argc = 0;
295   va_start (ap, filename);
296   while (NULL != va_arg (ap, char *))
297       argc++;
298   va_end (ap);
299   argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
300   argc = 0;
301   va_start (ap, filename);
302   while (NULL != (argv[argc] = va_arg (ap, char *)))
303     argc++;
304   va_end (ap);
305   if (pipe_stdout != NULL)
306     {
307       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int));
308       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_READ), &fd_stdout_read, sizeof (int));
309     }
310   if (pipe_stdin != NULL)
311     {
312       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &fd_stdin_read, sizeof (int));
313       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_WRITE), &fd_stdin_write, sizeof (int));
314     }
315
316 #if HAVE_WORKING_VFORK
317   ret = vfork ();
318 #else
319   ret = fork ();
320 #endif
321   if (ret != 0)
322     {
323       if (ret == -1)
324         {
325           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
326         }
327       else
328         {
329
330 #if HAVE_WORKING_VFORK
331           /* let's hope vfork actually works; for some extreme cases (including
332              a testcase) we need 'execvp' to have run before we return, since
333              we may send a signal to the process next and we don't want it
334              to be caught by OUR signal handler (but either by the default
335              handler or the actual handler as installed by the process itself). */
336 #else
337           /* let's give the child process a chance to run execvp, 1s should
338              be plenty in practice */
339           if (pipe_stdout != NULL)
340             GNUNET_DISK_pipe_close_end(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
341           if (pipe_stdin != NULL)
342             GNUNET_DISK_pipe_close_end(pipe_stdin, GNUNET_DISK_PIPE_END_READ);
343           sleep (1);
344 #endif
345           gnunet_proc = GNUNET_OS_process_alloc ();
346           GNUNET_OS_process_set_pid (gnunet_proc, ret);
347         }
348       GNUNET_free (argv);
349       return gnunet_proc;
350     }
351
352   if (pipe_stdout != NULL)
353     {
354       GNUNET_break (0 == close (fd_stdout_read));
355       if (-1 == dup2(fd_stdout_write, 1))
356         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");  
357       GNUNET_break (0 == close (fd_stdout_write));
358     }
359
360   if (pipe_stdin != NULL)
361     {
362
363       GNUNET_break (0 == close (fd_stdin_write));
364       if (-1 == dup2(fd_stdin_read, 0))
365         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup2");  
366       GNUNET_break (0 == close (fd_stdin_read));
367     }
368   execvp (filename, argv);
369   GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
370   _exit (1);
371 #else
372   char *arg;
373   unsigned int cmdlen;
374   char *cmd, *idx;
375   int findresult;
376   STARTUPINFO start;
377   PROCESS_INFORMATION proc;
378   GNUNET_OS_Process *gnunet_proc = NULL;
379
380   HANDLE stdin_handle;
381   HANDLE stdout_handle;
382
383   char path[MAX_PATH + 1];
384
385   cmdlen = 0;
386   va_start (ap, filename);
387   while (NULL != (arg = va_arg (ap, char *)))
388       cmdlen = cmdlen + strlen (arg) + 3;
389   va_end (ap);
390
391   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
392   va_start (ap, filename);
393   while (NULL != (arg = va_arg (ap, char *)))
394       idx += sprintf (idx, "\"%s\" ", arg);
395   va_end (ap);
396
397   memset (&start, 0, sizeof (start));
398   start.cb = sizeof (start);
399
400   if ((pipe_stdin != NULL) || (pipe_stdout != NULL))
401     start.dwFlags |= STARTF_USESTDHANDLES;
402
403   if (pipe_stdin != NULL)
404     {
405       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE));
406       start.hStdInput = stdin_handle;
407     }
408
409   if (pipe_stdout != NULL)
410     {
411       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE));
412       start.hStdOutput = stdout_handle;
413     }
414
415   findresult = (int) FindExecutableA (filename, NULL, path);
416   if (findresult <= 32) 
417     {
418       SetErrnoFromWinError (GetLastError ());
419       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
420       return NULL;
421     }
422
423   if (!CreateProcessA
424       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
425        &proc))
426     {
427       SetErrnoFromWinError (GetLastError ());
428       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
429       return NULL;
430     }
431
432   gnunet_proc = GNUNET_OS_process_alloc ();
433   GNUNET_OS_process_set_pid (gnunet_proc, proc.dwProcessId);
434   GNUNET_OS_process_set_handle (gnunet_proc, proc.hProcess);
435
436   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
437
438   CloseHandle (proc.hThread);
439
440   GNUNET_free (cmd);
441
442   return gnunet_proc;
443 #endif
444
445 }
446
447
448
449 /**
450  * Start a process.
451  *
452  * @param lsocks array of listen sockets to dup systemd-style (or NULL);
453  *         must be NULL on platforms where dup is not supported
454  * @param filename name of the binary
455  * @param argv NULL-terminated list of arguments to the process
456  * @return process ID of the new process, -1 on error
457  */
458 GNUNET_OS_Process *
459 GNUNET_OS_start_process_v (const int *lsocks,
460                            const char *filename, char *const argv[])
461 {
462 #ifndef MINGW
463   pid_t ret;
464   char lpid[16];
465   char fds[16];
466   GNUNET_OS_Process *gnunet_proc = NULL;
467   int i;
468   int j;
469   int k;
470   int tgt;
471   int flags;
472   int *lscp;
473   unsigned int ls;    
474
475   lscp = NULL;
476   ls = 0;
477   if (lsocks != NULL)
478     {
479       i = 0;
480       while (-1 != (k = lsocks[i++]))
481         GNUNET_array_append (lscp, ls, k);      
482       GNUNET_array_append (lscp, ls, -1);
483     }
484 #if HAVE_WORKING_VFORK
485   ret = vfork ();
486 #else
487   ret = fork ();
488 #endif
489   if (ret != 0)
490     {
491       if (ret == -1)
492         {
493           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
494         }
495       else
496         {
497 #if HAVE_WORKING_VFORK
498           /* let's hope vfork actually works; for some extreme cases (including
499              a testcase) we need 'execvp' to have run before we return, since
500              we may send a signal to the process next and we don't want it
501              to be caught by OUR signal handler (but either by the default
502              handler or the actual handler as installed by the process itself). */
503 #else
504           /* let's give the child process a chance to run execvp, 1s should
505              be plenty in practice */
506           sleep (1);
507 #endif
508           gnunet_proc = GNUNET_OS_process_alloc ();
509           GNUNET_OS_process_set_pid (gnunet_proc, ret);
510         }
511       GNUNET_array_grow (lscp, ls, 0);
512       return gnunet_proc;
513     }
514   if (lscp != NULL)
515     {
516       /* read systemd documentation... */
517       GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid());
518       setenv ("LISTEN_PID", lpid, 1);      
519       i = 0;
520       tgt = 3;
521       while (-1 != lscp[i])
522         {
523           j = i + 1;
524           while (-1 != lscp[j])
525             {
526               if (lscp[j] == tgt)
527                 {
528                   /* dup away */
529                   k = dup (lscp[j]);
530                   GNUNET_assert (-1 != k);
531                   GNUNET_assert (0 == close (lscp[j]));
532                   lscp[j] = k;
533                   break;
534                 }
535               j++;
536             }
537           if (lscp[i] != tgt)
538             {
539               /* Bury any existing FD, no matter what; they should all be closed
540                  on exec anyway and the important onces have been dup'ed away */
541               (void) close (tgt);             
542               GNUNET_assert (-1 != dup2 (lscp[i], tgt));
543             }
544           /* unset close-on-exec flag */
545           flags = fcntl (tgt, F_GETFD);
546           GNUNET_assert (flags >= 0);
547           flags &= ~FD_CLOEXEC;
548           fflush (stderr);
549           (void) fcntl (tgt, F_SETFD, flags);
550           tgt++;
551           i++;
552         }
553       GNUNET_snprintf (fds, sizeof (fds), "%u", i);
554       setenv ("LISTEN_FDS", fds, 1); 
555     }
556   GNUNET_array_grow (lscp, ls, 0);
557   execvp (filename, argv);
558   GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
559   _exit (1);
560 #else
561   char **arg, **non_const_argv;
562   unsigned int cmdlen;
563   char *cmd, *idx;
564   STARTUPINFO start;
565   PROCESS_INFORMATION proc;
566   int argcount = 0;
567   char *non_const_filename = NULL;
568   int filenamelen = 0;
569   GNUNET_OS_Process *gnunet_proc = NULL;
570
571   GNUNET_assert (lsocks == NULL);
572   /* Count the number of arguments */
573   arg = (char **) argv;
574   while (*arg)
575     {
576       arg++;
577       argcount++;
578     }
579
580   /* Allocate a copy argv */
581   non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
582
583   /* Copy all argv strings */
584   argcount = 0;
585   arg = (char **) argv;
586   while (*arg)
587     {
588       non_const_argv[argcount] = GNUNET_strdup (*arg);
589       arg++;
590       argcount++;
591     }
592   non_const_argv[argcount] = NULL;
593
594   /* Fix .exe extension */
595   filenamelen = strlen (filename);
596   if (filenamelen <= 4 || stricmp (&filename[filenamelen - 4], ".exe") != 0)
597   {
598     non_const_filename = GNUNET_malloc (sizeof (char) * (filenamelen + 4 + 1));
599     non_const_filename = strcpy (non_const_filename, non_const_argv[0]);
600     strcat (non_const_filename, ".exe");
601     GNUNET_free (non_const_argv[0]);
602     non_const_argv[0] = non_const_filename;
603   }
604   else
605     non_const_filename = non_const_argv[0];
606
607   /* Count cmd len */
608   cmdlen = 1;
609   arg = non_const_argv;
610   while (*arg)
611     {
612       cmdlen = cmdlen + strlen (*arg) + 3;
613       arg++;
614     }
615
616   /* Allocate and create cmd */
617   cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
618   arg = non_const_argv;
619   while (*arg)
620     {
621       idx += sprintf (idx, "\"%s\" ", *arg);
622       arg++;
623     }
624
625   memset (&start, 0, sizeof (start));
626   start.cb = sizeof (start);
627
628   if (!CreateProcess
629       (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
630        &proc))
631     {
632       SetErrnoFromWinError (GetLastError ());
633       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
634       return NULL;
635     }
636
637   gnunet_proc = GNUNET_OS_process_alloc ();
638   GNUNET_OS_process_set_pid (gnunet_proc, proc.dwProcessId);
639   GNUNET_OS_process_set_handle (gnunet_proc, proc.hProcess);
640
641   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
642
643   CloseHandle (proc.hThread);
644   GNUNET_free (cmd);
645
646   while (argcount > 0)
647     GNUNET_free (non_const_argv[--argcount]);
648   GNUNET_free (non_const_argv);
649
650   return gnunet_proc;
651 #endif
652 }
653
654 /**
655  * Retrieve the status of a process
656  * @param proc process ID
657  * @param type status type
658  * @param code return code/signal number
659  * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
660  */
661 int
662 GNUNET_OS_process_status (GNUNET_OS_Process *proc, enum GNUNET_OS_ProcessStatusType *type,
663                           unsigned long *code)
664 {
665 #ifndef MINGW
666   int status;
667   int ret;
668
669   GNUNET_assert (0 != proc);
670   ret = waitpid (GNUNET_OS_process_get_pid (proc), &status, WNOHANG);
671   if (ret < 0)
672     {
673       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
674       return GNUNET_SYSERR;
675     }
676   if (0 == ret)
677     {
678       *type = GNUNET_OS_PROCESS_RUNNING;
679       *code = 0;
680       return GNUNET_NO;
681     }
682   if (GNUNET_OS_process_get_pid (proc) != ret)
683     {
684       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
685       return GNUNET_SYSERR;
686     }
687   if (WIFEXITED (status))
688     {
689       *type = GNUNET_OS_PROCESS_EXITED;
690       *code = WEXITSTATUS (status);
691     }
692   else if (WIFSIGNALED (status))
693     {
694       *type = GNUNET_OS_PROCESS_SIGNALED;
695       *code = WTERMSIG (status);
696     }
697   else if (WIFSTOPPED (status))
698     {
699       *type = GNUNET_OS_PROCESS_SIGNALED;
700       *code = WSTOPSIG (status);
701     }
702 #ifdef WIFCONTINUED
703   else if (WIFCONTINUED (status))
704     {
705       *type = GNUNET_OS_PROCESS_RUNNING;
706       *code = 0;
707     }
708 #endif
709   else
710     {
711       *type = GNUNET_OS_PROCESS_UNKNOWN;
712       *code = 0;
713     }
714 #else
715   HANDLE h;
716   DWORD c, error_code, ret;
717
718   h = GNUNET_OS_process_get_handle (proc);
719   ret = GNUNET_OS_process_get_pid (proc);
720   if (h == NULL || ret == 0)
721     {
722       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", ret, h);
723       return GNUNET_SYSERR;
724     }
725   if (h == NULL)
726     h = GetCurrentProcess ();
727
728   SetLastError (0);
729   ret = GetExitCodeProcess (h, &c);
730   error_code = GetLastError ();
731   if (ret == 0 || error_code != NO_ERROR)
732   {
733       SetErrnoFromWinError (error_code);
734       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
735       return GNUNET_SYSERR;
736   }
737   if (STILL_ACTIVE == c)
738     {
739       *type = GNUNET_OS_PROCESS_RUNNING;
740       *code = 0;
741       return GNUNET_NO;
742     }
743   *type = GNUNET_OS_PROCESS_EXITED;
744   *code = c;
745 #endif
746
747   return GNUNET_OK;
748 }
749
750 /**
751  * Wait for a process
752  * @param proc pointer to process structure
753  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
754  */
755 int
756 GNUNET_OS_process_wait (GNUNET_OS_Process *proc)
757 {
758   pid_t pid = GNUNET_OS_process_get_pid (proc);
759 #ifndef MINGW
760   if (pid != waitpid (pid, NULL, 0))
761     return GNUNET_SYSERR;
762
763   return GNUNET_OK;
764 #else
765   HANDLE h;
766   int ret;
767
768   h = GNUNET_OS_process_get_handle (proc);
769   if (NULL == h)
770     {
771       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", pid, h);
772       return GNUNET_SYSERR;
773     }
774   if (h == NULL)
775     h = GetCurrentProcess ();
776
777   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
778     {
779       SetErrnoFromWinError (GetLastError ());
780       ret = GNUNET_SYSERR;
781     }
782   else
783     ret = GNUNET_OK;
784
785   return ret;
786 #endif
787 }
788
789
790 /* end of os_priority.c */