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