another LRN patch
[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   int filenamelen = 0;
555   struct GNUNET_OS_Process *gnunet_proc = NULL;
556
557   GNUNET_assert (lsocks == NULL);
558
559   if (32 >= FindExecutableA (filename, NULL, non_const_filename)) 
560     {
561       SetErrnoFromWinError (GetLastError ());
562       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
563       return NULL;
564     }
565
566   /* Count the number of arguments */
567   arg = (char **) argv;
568   while (*arg)
569     {
570       arg++;
571       argcount++;
572     }
573
574   /* Allocate a copy argv */
575   non_const_argv = GNUNET_malloc (sizeof (char *) * (argcount + 1));
576
577   /* Copy all argv strings */
578   argcount = 0;
579   arg = (char **) argv;
580   while (*arg)
581     {
582       non_const_argv[argcount] = GNUNET_strdup (*arg);
583       arg++;
584       argcount++;
585     }
586   non_const_argv[argcount] = NULL;
587
588   /* Count cmd len */
589   cmdlen = 1;
590   arg = non_const_argv;
591   while (*arg)
592     {
593       cmdlen = cmdlen + strlen (*arg) + 3;
594       arg++;
595     }
596
597   /* Allocate and create cmd */
598   cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
599   arg = non_const_argv;
600   while (*arg)
601     {
602       idx += sprintf (idx, "\"%s\" ", *arg);
603       arg++;
604     }
605
606   memset (&start, 0, sizeof (start));
607   start.cb = sizeof (start);
608
609   if (!CreateProcess
610       (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
611        &proc))
612     {
613       SetErrnoFromWinError (GetLastError ());
614       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
615       return NULL;
616     }
617
618   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
619   gnunet_proc->pid = proc.dwProcessId;
620   gnunet_proc->handle = proc.hProcess;
621
622   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
623
624   CloseHandle (proc.hThread);
625   GNUNET_free (cmd);
626
627   while (argcount > 0)
628     GNUNET_free (non_const_argv[--argcount]);
629   GNUNET_free (non_const_argv);
630
631   return gnunet_proc;
632 #endif
633 }
634
635 /**
636  * Retrieve the status of a process
637  * @param proc process ID
638  * @param type status type
639  * @param code return code/signal number
640  * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
641  */
642 int
643 GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, 
644                           enum GNUNET_OS_ProcessStatusType *type,
645                           unsigned long *code)
646 {
647 #ifndef MINGW
648   int status;
649   int ret;
650
651   GNUNET_assert (0 != proc);
652   ret = waitpid (proc->pid, &status, WNOHANG);
653   if (ret < 0)
654     {
655       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
656       return GNUNET_SYSERR;
657     }
658   if (0 == ret)
659     {
660       *type = GNUNET_OS_PROCESS_RUNNING;
661       *code = 0;
662       return GNUNET_NO;
663     }
664   if (proc->pid != ret)
665     {
666       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
667       return GNUNET_SYSERR;
668     }
669   if (WIFEXITED (status))
670     {
671       *type = GNUNET_OS_PROCESS_EXITED;
672       *code = WEXITSTATUS (status);
673     }
674   else if (WIFSIGNALED (status))
675     {
676       *type = GNUNET_OS_PROCESS_SIGNALED;
677       *code = WTERMSIG (status);
678     }
679   else if (WIFSTOPPED (status))
680     {
681       *type = GNUNET_OS_PROCESS_SIGNALED;
682       *code = WSTOPSIG (status);
683     }
684 #ifdef WIFCONTINUED
685   else if (WIFCONTINUED (status))
686     {
687       *type = GNUNET_OS_PROCESS_RUNNING;
688       *code = 0;
689     }
690 #endif
691   else
692     {
693       *type = GNUNET_OS_PROCESS_UNKNOWN;
694       *code = 0;
695     }
696 #else
697   HANDLE h;
698   DWORD c, error_code, ret;
699
700   h = proc->handle;
701   ret = proc->pid;
702   if (h == NULL || ret == 0)
703     {
704       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid process information {%d, %08X}\n", ret, h);
705       return GNUNET_SYSERR;
706     }
707   if (h == NULL)
708     h = GetCurrentProcess ();
709
710   SetLastError (0);
711   ret = GetExitCodeProcess (h, &c);
712   error_code = GetLastError ();
713   if (ret == 0 || error_code != NO_ERROR)
714   {
715       SetErrnoFromWinError (error_code);
716       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "GetExitCodeProcess");
717       return GNUNET_SYSERR;
718   }
719   if (STILL_ACTIVE == c)
720     {
721       *type = GNUNET_OS_PROCESS_RUNNING;
722       *code = 0;
723       return GNUNET_NO;
724     }
725   *type = GNUNET_OS_PROCESS_EXITED;
726   *code = c;
727 #endif
728
729   return GNUNET_OK;
730 }
731
732 /**
733  * Wait for a process
734  * @param proc pointer to process structure
735  * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
736  */
737 int
738 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
739 {
740
741 #ifndef MINGW
742   pid_t pid = proc->pid;
743   if (pid != waitpid (pid, NULL, 0))
744     return GNUNET_SYSERR;
745   return GNUNET_OK;
746 #else
747   HANDLE h;
748   int ret;
749
750   h = proc->handle;
751   if (NULL == h)
752     {
753       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
754                   "Invalid process information {%d, %08X}\n", 
755                   proc->pid, 
756                   h);
757       return GNUNET_SYSERR;
758     }
759   if (h == NULL)
760     h = GetCurrentProcess ();
761
762   if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
763     {
764       SetErrnoFromWinError (GetLastError ());
765       ret = GNUNET_SYSERR;
766     }
767   else
768     ret = GNUNET_OK;
769
770   return ret;
771 #endif
772 }
773
774
775 /* end of os_priority.c */