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