baeeb2d9ad29e8825ef403d422b7227edac3a41f
[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  * @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   STARTUPINFO start;
364   PROCESS_INFORMATION proc;
365   struct GNUNET_OS_Process *gnunet_proc = NULL;
366
367   HANDLE stdin_handle;
368   HANDLE stdout_handle;
369
370   char path[MAX_PATH + 1];
371
372   cmdlen = 0;
373   va_start (ap, filename);
374   while (NULL != (arg = va_arg (ap, char *)))
375       cmdlen = cmdlen + strlen (arg) + 3;
376   va_end (ap);
377
378   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
379   va_start (ap, filename);
380   while (NULL != (arg = va_arg (ap, char *)))
381       idx += sprintf (idx, "\"%s\" ", arg);
382   va_end (ap);
383
384   memset (&start, 0, sizeof (start));
385   start.cb = sizeof (start);
386
387   if ((pipe_stdin != NULL) || (pipe_stdout != NULL))
388     start.dwFlags |= STARTF_USESTDHANDLES;
389
390   if (pipe_stdin != NULL)
391     {
392       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE));
393       start.hStdInput = stdin_handle;
394     }
395
396   if (pipe_stdout != NULL)
397     {
398       GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE));
399       start.hStdOutput = stdout_handle;
400     }
401
402   if (32 >= FindExecutableA (filename, NULL, path)) 
403     {
404       SetErrnoFromWinError (GetLastError ());
405       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
406       return NULL;
407     }
408
409   if (!CreateProcessA
410       (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
411        &proc))
412     {
413       SetErrnoFromWinError (GetLastError ());
414       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
415       return NULL;
416     }
417
418   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
419   gnunet_proc->pid = proc.dwProcessId;
420   gnunet_proc->handle = proc.hProcess;
421
422   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
423
424   CloseHandle (proc.hThread);
425
426   GNUNET_free (cmd);
427
428   return gnunet_proc;
429 #endif
430
431 }
432
433
434
435 /**
436  * Start a process.
437  *
438  * @param lsocks array of listen sockets to dup systemd-style (or NULL);
439  *         must be NULL on platforms where dup is not supported
440  * @param filename name of the binary
441  * @param argv NULL-terminated list of arguments to the process
442  * @return process ID of the new process, -1 on error
443  */
444 struct GNUNET_OS_Process *
445 GNUNET_OS_start_process_v (const int *lsocks,
446                            const char *filename, char *const argv[])
447 {
448 #ifndef MINGW
449   pid_t ret;
450   char lpid[16];
451   char fds[16];
452   struct GNUNET_OS_Process *gnunet_proc = NULL;
453   int i;
454   int j;
455   int k;
456   int tgt;
457   int flags;
458   int *lscp;
459   unsigned int ls;    
460
461   lscp = NULL;
462   ls = 0;
463   if (lsocks != NULL)
464     {
465       i = 0;
466       while (-1 != (k = lsocks[i++]))
467         GNUNET_array_append (lscp, ls, k);      
468       GNUNET_array_append (lscp, ls, -1);
469     }
470 #if HAVE_WORKING_VFORK
471   ret = vfork ();
472 #else
473   ret = fork ();
474 #endif
475   if (ret != 0)
476     {
477       if (ret == -1)
478         {
479           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
480         }
481       else
482         {
483 #if HAVE_WORKING_VFORK
484           /* let's hope vfork actually works; for some extreme cases (including
485              a testcase) we need 'execvp' to have run before we return, since
486              we may send a signal to the process next and we don't want it
487              to be caught by OUR signal handler (but either by the default
488              handler or the actual handler as installed by the process itself). */
489 #else
490           /* let's give the child process a chance to run execvp, 1s should
491              be plenty in practice */
492           sleep (1);
493 #endif
494           gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
495           gnunet_proc->pid = ret;
496         }
497       GNUNET_array_grow (lscp, ls, 0);
498       return gnunet_proc;
499     }
500   if (lscp != NULL)
501     {
502       /* read systemd documentation... */
503       GNUNET_snprintf (lpid, sizeof (lpid), "%u", getpid());
504       setenv ("LISTEN_PID", lpid, 1);      
505       i = 0;
506       tgt = 3;
507       while (-1 != lscp[i])
508         {
509           j = i + 1;
510           while (-1 != lscp[j])
511             {
512               if (lscp[j] == tgt)
513                 {
514                   /* dup away */
515                   k = dup (lscp[j]);
516                   GNUNET_assert (-1 != k);
517                   GNUNET_assert (0 == close (lscp[j]));
518                   lscp[j] = k;
519                   break;
520                 }
521               j++;
522             }
523           if (lscp[i] != tgt)
524             {
525               /* Bury any existing FD, no matter what; they should all be closed
526                  on exec anyway and the important onces have been dup'ed away */
527               (void) close (tgt);             
528               GNUNET_assert (-1 != dup2 (lscp[i], tgt));
529             }
530           /* unset close-on-exec flag */
531           flags = fcntl (tgt, F_GETFD);
532           GNUNET_assert (flags >= 0);
533           flags &= ~FD_CLOEXEC;
534           fflush (stderr);
535           (void) fcntl (tgt, F_SETFD, flags);
536           tgt++;
537           i++;
538         }
539       GNUNET_snprintf (fds, sizeof (fds), "%u", i);
540       setenv ("LISTEN_FDS", fds, 1); 
541     }
542   GNUNET_array_grow (lscp, ls, 0);
543   execvp (filename, argv);
544   GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
545   _exit (1);
546 #else
547   char **arg, **non_const_argv;
548   unsigned int cmdlen;
549   char *cmd, *idx;
550   STARTUPINFO start;
551   PROCESS_INFORMATION proc;
552   int argcount = 0;
553   char non_const_filename[MAX_PATH +1];
554   struct GNUNET_OS_Process *gnunet_proc = NULL;
555
556   GNUNET_assert (lsocks == NULL);
557
558   if (32 >= FindExecutableA (filename, NULL, non_const_filename)) 
559     {
560       SetErrnoFromWinError (GetLastError ());
561       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
562       return NULL;
563     }
564
565   /* Count the number of arguments */
566   arg = (char **) argv;
567   while (*arg)
568     {
569       arg++;
570       argcount++;
571     }
572
573   /* Allocate a copy argv */
574   non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
575
576   /* Copy all argv strings */
577   argcount = 0;
578   arg = (char **) argv;
579   while (*arg)
580     {
581       non_const_argv[argcount] = GNUNET_strdup (*arg);
582       arg++;
583       argcount++;
584     }
585   non_const_argv[argcount] = NULL;
586
587   /* Count cmd len */
588   cmdlen = 1;
589   arg = non_const_argv;
590   while (*arg)
591     {
592       cmdlen = cmdlen + strlen (*arg) + 3;
593       arg++;
594     }
595
596   /* Allocate and create cmd */
597   cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
598   arg = non_const_argv;
599   while (*arg)
600     {
601       idx += sprintf (idx, "\"%s\" ", *arg);
602       arg++;
603     }
604
605   memset (&start, 0, sizeof (start));
606   start.cb = sizeof (start);
607
608   if (!CreateProcess
609       (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
610        &proc))
611     {
612       SetErrnoFromWinError (GetLastError ());
613       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
614       return NULL;
615     }
616
617   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
618   gnunet_proc->pid = proc.dwProcessId;
619   gnunet_proc->handle = proc.hProcess;
620
621   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
622
623   CloseHandle (proc.hThread);
624   GNUNET_free (cmd);
625
626   while (argcount > 0)
627     GNUNET_free (non_const_argv[--argcount]);
628   GNUNET_free (non_const_argv);
629
630   return gnunet_proc;
631 #endif
632 }
633
634 /**
635  * Retrieve the status of a process
636  * @param proc process ID
637  * @param type status type
638  * @param code return code/signal number
639  * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
640  */
641 int
642 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, 
643                           enum GNUNET_OS_ProcessStatusType *type,
644                           unsigned long *code)
645 {
646 #ifndef MINGW
647   int status;
648   int ret;
649
650   GNUNET_assert (0 != proc);
651   ret = waitpid (proc->pid, &status, WNOHANG);
652   if (ret < 0)
653     {
654       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
655       return GNUNET_SYSERR;
656     }
657   if (0 == ret)
658     {
659       *type = GNUNET_OS_PROCESS_RUNNING;
660       *code = 0;
661       return GNUNET_NO;
662     }
663   if (proc->pid != ret)
664     {
665       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
666       return GNUNET_SYSERR;
667     }
668   if (WIFEXITED (status))
669     {
670       *type = GNUNET_OS_PROCESS_EXITED;
671       *code = WEXITSTATUS (status);
672     }
673   else if (WIFSIGNALED (status))
674     {
675       *type = GNUNET_OS_PROCESS_SIGNALED;
676       *code = WTERMSIG (status);
677     }
678   else if (WIFSTOPPED (status))
679     {
680       *type = GNUNET_OS_PROCESS_SIGNALED;
681       *code = WSTOPSIG (status);
682     }
683 #ifdef WIFCONTINUED
684   else if (WIFCONTINUED (status))
685     {
686       *type = GNUNET_OS_PROCESS_RUNNING;
687       *code = 0;
688     }
689 #endif
690   else
691     {
692       *type = GNUNET_OS_PROCESS_UNKNOWN;
693       *code = 0;
694     }
695 #else
696   HANDLE h;
697   DWORD c, error_code, ret;
698
699   h = proc->handle;
700   ret = proc->pid;
701   if (h == NULL || ret == 0)
702     {
703       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", ret, h);
704       return GNUNET_SYSERR;
705     }
706   if (h == NULL)
707     h = GetCurrentProcess ();
708
709   SetLastError (0);
710   ret = GetExitCodeProcess (h, &c);
711   error_code = GetLastError ();
712   if (ret == 0 || error_code != NO_ERROR)
713   {
714       SetErrnoFromWinError (error_code);
715       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
716       return GNUNET_SYSERR;
717   }
718   if (STILL_ACTIVE == c)
719     {
720       *type = GNUNET_OS_PROCESS_RUNNING;
721       *code = 0;
722       return GNUNET_NO;
723     }
724   *type = GNUNET_OS_PROCESS_EXITED;
725   *code = c;
726 #endif
727
728   return GNUNET_OK;
729 }
730
731 /**
732  * Wait for a process
733  * @param proc pointer to process structure
734  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
735  */
736 int
737 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
738 {
739
740 #ifndef MINGW
741   pid_t pid = proc->pid;
742   if (pid != waitpid (pid, NULL, 0))
743     return GNUNET_SYSERR;
744   return GNUNET_OK;
745 #else
746   HANDLE h;
747   int ret;
748
749   h = proc->handle;
750   if (NULL == h)
751     {
752       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
753                   "Invalid process information {%d, %08X}\n", 
754                   proc->pid, 
755                   h);
756       return GNUNET_SYSERR;
757     }
758   if (h == NULL)
759     h = GetCurrentProcess ();
760
761   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
762     {
763       SetErrnoFromWinError (GetLastError ());
764       ret = GNUNET_SYSERR;
765     }
766   else
767     ret = GNUNET_OK;
768
769   return ret;
770 #endif
771 }
772
773
774 /* end of os_priority.c */