-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / util / os_priority.c
index 8dfec6c5e8bddb208262abed9b77ca13cf21e5c7..a758f24f1da7678eb006f315a464e24e9458b550 100644 (file)
@@ -2,20 +2,18 @@
      This file is part of GNUnet
      Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
 
      This file is part of GNUnet
      Copyright (C) 2002, 2003, 2004, 2005, 2006, 2011 GNUnet e.V.
 
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     Affero General Public License for more details.
+    
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /**
 */
 
 /**
 #include "disk.h"
 #include <unistr.h>
 
 #include "disk.h"
 #include <unistr.h>
 
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-os-priority", __VA_ARGS__)
 
 
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-os-priority", syscall)
 
 
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-os-priority", syscall, filename)
 
 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
 
 
 #define GNUNET_OS_CONTROL_PIPE "GNUNET_OS_CONTROL_PIPE"
 
@@ -65,49 +63,75 @@ struct GNUNET_OS_Process
  */
 static struct GNUNET_OS_Process current_process;
 
  */
 static struct GNUNET_OS_Process current_process;
 
+/**
+ * Handle for the #parent_control_handler() Task.
+ */
+static struct GNUNET_SCHEDULER_Task *pch;
+
+/**
+ * Handle for the #shutdown_pch() Task.
+ */
+static struct GNUNET_SCHEDULER_Task *spch;
+
+
+/**
+ * This handler is called on shutdown to remove the #pch.
+ *
+ * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
+ */
+static void
+shutdown_pch (void *cls)
+{
+  struct GNUNET_DISK_FileHandle *control_pipe = cls;
+
+  GNUNET_SCHEDULER_cancel (pch);
+  pch = NULL;
+  GNUNET_DISK_file_close (control_pipe);
+  control_pipe = NULL;
+}
+
 
 /**
  * This handler is called when there are control data to be read on the pipe
  *
 
 /**
  * This handler is called when there are control data to be read on the pipe
  *
- * @param cls the 'struct GNUNET_DISK_FileHandle' of the control pipe
+ * @param cls the `struct GNUNET_DISK_FileHandle` of the control pipe
  */
 static void
 parent_control_handler (void *cls)
 {
   struct GNUNET_DISK_FileHandle *control_pipe = cls;
  */
 static void
 parent_control_handler (void *cls)
 {
   struct GNUNET_DISK_FileHandle *control_pipe = cls;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
   char sig;
   char *pipe_fd;
   ssize_t ret;
 
   char sig;
   char *pipe_fd;
   ssize_t ret;
 
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "`%s' invoked because of %d\n", __FUNCTION__,
-       tc->reason);
-  if (0 != (tc->reason &
-           (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT)))
-  {
-    GNUNET_DISK_file_close (control_pipe);
-    control_pipe = NULL;
-    return;
-  }
-  ret = GNUNET_DISK_file_read (control_pipe, &sig, sizeof (sig));
+  pch = NULL;
+  ret = GNUNET_DISK_file_read (control_pipe,
+                              &sig,
+                              sizeof (sig));
   if (sizeof (sig) != ret)
   {
     if (-1 == ret)
   if (sizeof (sig) != ret)
   {
     if (-1 == ret)
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "GNUNET_DISK_file_read");
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Closing control pipe\n");
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                   "GNUNET_DISK_file_read");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Closing control pipe\n");
     GNUNET_DISK_file_close (control_pipe);
     control_pipe = NULL;
     GNUNET_DISK_file_close (control_pipe);
     control_pipe = NULL;
+    GNUNET_SCHEDULER_cancel (spch);
+    spch = NULL;
     return;
   }
   pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
     return;
   }
   pipe_fd = getenv (GNUNET_OS_CONTROL_PIPE);
-  GNUNET_assert ( (NULL == pipe_fd) || (strlen (pipe_fd) <= 0) );
+  GNUNET_assert ( (NULL == pipe_fd) ||
+                 (strlen (pipe_fd) <= 0) );
   LOG (GNUNET_ERROR_TYPE_DEBUG,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got control code %d from parent via pipe %s\n", sig, pipe_fd);
-  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                 control_pipe, &parent_control_handler,
-                                 control_pipe);
+       "Got control code %d from parent via pipe %s\n",
+       sig,
+       pipe_fd);
+  pch = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+                                       control_pipe,
+                                       &parent_control_handler,
+                                       control_pipe);
   GNUNET_SIGNAL_raise ((int) sig);
 }
 
   GNUNET_SIGNAL_raise ((int) sig);
 }
 
@@ -115,7 +139,7 @@ parent_control_handler (void *cls)
 /**
  * Task that connects this process to its parent via pipe;
  * essentially, the parent control handler will read signal numbers
 /**
  * Task that connects this process to its parent via pipe;
  * essentially, the parent control handler will read signal numbers
- * from the 'GNUNET_OS_CONTROL_PIPE' (as given in an environment
+ * from the #GNUNET_OS_CONTROL_PIPE (as given in an environment
  * variable) and raise those signals.
  *
  * @param cls closure (unused)
  * variable) and raise those signals.
  *
  * @param cls closure (unused)
@@ -128,6 +152,13 @@ GNUNET_OS_install_parent_control_handler (void *cls)
   struct GNUNET_DISK_FileHandle *control_pipe;
   uint64_t pipe_fd;
 
   struct GNUNET_DISK_FileHandle *control_pipe;
   uint64_t pipe_fd;
 
+  (void) cls;
+  if (NULL != pch)
+  {
+    /* already done, we've been called twice... */
+    GNUNET_break (0);
+    return;
+  }
   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
   if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
   {
   env_buf = getenv (GNUNET_OS_CONTROL_PIPE);
   if ( (NULL == env_buf) || (strlen (env_buf) <= 0) )
   {
@@ -141,7 +172,9 @@ GNUNET_OS_install_parent_control_handler (void *cls)
   pipe_fd = strtoull (env_buf, &env_buf_end, 16);
   if ((0 != errno) || (env_buf == env_buf_end))
   {
   pipe_fd = strtoull (env_buf, &env_buf_end, 16);
   if ((0 != errno) || (env_buf == env_buf_end))
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "strtoull", env_buf);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
+                      "strtoull",
+                      env_buf);
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
@@ -153,7 +186,8 @@ GNUNET_OS_install_parent_control_handler (void *cls)
 #endif
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
 #endif
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
-         "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n", env_buf);
+         "GNUNET_OS_CONTROL_PIPE `%s' contains garbage?\n",
+        env_buf);
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
@@ -164,14 +198,21 @@ GNUNET_OS_install_parent_control_handler (void *cls)
 #endif
   if (NULL == control_pipe)
   {
 #endif
   if (NULL == control_pipe)
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", env_buf);
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
+                      "open",
+                      env_buf);
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
     putenv (GNUNET_OS_CONTROL_PIPE "=");
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding parent control handler pipe `%s' to the scheduler\n", env_buf);
-  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, control_pipe,
-                                  &parent_control_handler, control_pipe);
+       "Adding parent control handler pipe `%s' to the scheduler\n",
+       env_buf);
+  pch = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+                                       control_pipe,
+                                       &parent_control_handler,
+                                       control_pipe);
+  spch = GNUNET_SCHEDULER_add_shutdown (&shutdown_pch,
+                                        control_pipe);
   putenv (GNUNET_OS_CONTROL_PIPE "=");
 }
 
   putenv (GNUNET_OS_CONTROL_PIPE "=");
 }
 
@@ -179,8 +220,8 @@ GNUNET_OS_install_parent_control_handler (void *cls)
 /**
  * Get process structure for current process
  *
 /**
  * Get process structure for current process
  *
- * The pointer it returns points to static memory location and must not be
- * deallocated/closed
+ * The pointer it returns points to static memory location and must
+ * not be deallocated/closed.
  *
  * @return pointer to the process sturcutre for this process
  */
  *
  * @return pointer to the process sturcutre for this process
  */
@@ -205,7 +246,8 @@ GNUNET_OS_process_current ()
  * @return 0 on success, -1 on error
  */
 int
  * @return 0 on success, -1 on error
  */
 int
-GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
+GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc,
+                       int sig)
 {
   int ret;
   char csig;
 {
   int ret;
   char csig;
@@ -213,8 +255,13 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
   csig = (char) sig;
   if (NULL != proc->control_pipe)
   {
   csig = (char) sig;
   if (NULL != proc->control_pipe)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via pipe\n", sig, proc->pid);
-    ret = GNUNET_DISK_file_write (proc->control_pipe, &csig, sizeof (csig));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Sending signal %d to pid: %u via pipe\n",
+        sig,
+        proc->pid);
+    ret = GNUNET_DISK_file_write (proc->control_pipe,
+                                 &csig,
+                                 sizeof (csig));
     if (sizeof (csig) == ret)
       return 0;
   }
     if (sizeof (csig) == ret)
       return 0;
   }
@@ -237,14 +284,17 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
       if (0 != GetExitCodeProcess (proc->handle, &exitcode))
         must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
       if (GNUNET_YES == must_kill)
       if (0 != GetExitCodeProcess (proc->handle, &exitcode))
         must_kill = (exitcode == STILL_ACTIVE) ? GNUNET_YES : GNUNET_NO;
       if (GNUNET_YES == must_kill)
+      {
         if (0 == SafeTerminateProcess (proc->handle, 0, 0))
         {
           DWORD error_code = GetLastError ();
         if (0 == SafeTerminateProcess (proc->handle, 0, 0))
         {
           DWORD error_code = GetLastError ();
-          if ((error_code != WAIT_TIMEOUT) && (error_code != ERROR_PROCESS_ABORTED))
+          if ( (error_code != WAIT_TIMEOUT) &&
+              (error_code != ERROR_PROCESS_ABORTED) )
           {
             LOG ((error_code == ERROR_ACCESS_DENIED) ?
           {
             LOG ((error_code == ERROR_ACCESS_DENIED) ?
-                GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
-                "SafeTermiateProcess failed with code %lu\n", error_code);
+                GNUNET_ERROR_TYPE_INFO : GNUNET_ERROR_TYPE_WARNING,
+                "SafeTermiateProcess failed with code %lu\n",
+                error_code);
             /* The problem here is that a process that is already dying
              * might cause SafeTerminateProcess to fail with
              * ERROR_ACCESS_DENIED, but the process WILL die eventually.
             /* The problem here is that a process that is already dying
              * might cause SafeTerminateProcess to fail with
              * ERROR_ACCESS_DENIED, but the process WILL die eventually.
@@ -263,6 +313,7 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
             }
           }
         }
             }
           }
         }
+      }
     }
     return 0;
 #else
     }
     return 0;
 #else
@@ -277,12 +328,16 @@ GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
     errno = EINVAL;
     return -1;
 #else
     errno = EINVAL;
     return -1;
 #else
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending signal %d to pid: %u via system call\n", sig, proc->pid);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Sending signal %d to pid: %u via system call\n",
+        sig,
+        proc->pid);
     return PLIBC_KILL (proc->pid, sig);
 #endif
   }
 }
 
     return PLIBC_KILL (proc->pid, sig);
 #endif
   }
 }
 
+
 /**
  * Get the pid of the process in question
  *
 /**
  * Get the pid of the process in question
  *
@@ -298,7 +353,8 @@ GNUNET_OS_process_get_pid (struct GNUNET_OS_Process * proc)
 
 
 /**
 
 
 /**
- * Cleans up process structure contents (OS-dependent) and deallocates it
+ * Cleans up process structure contents (OS-dependent) and deallocates
+ * it.
  *
  * @param proc pointer to process structure
  */
  *
  * @param proc pointer to process structure
  */
@@ -314,6 +370,7 @@ GNUNET_OS_process_destroy (struct GNUNET_OS_Process *proc)
   GNUNET_free (proc);
 }
 
   GNUNET_free (proc);
 }
 
+
 #if WINDOWS
 #include "gnunet_signal_lib.h"
 
 #if WINDOWS
 #include "gnunet_signal_lib.h"
 
@@ -324,6 +381,7 @@ extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
  */
 #define DWORD_WINAPI DWORD WINAPI
 
  */
 #define DWORD_WINAPI DWORD WINAPI
 
+
 /**
  * @brief Waits for a process to terminate and invokes the SIGCHLD handler
  * @param proc pointer to process structure
 /**
  * @brief Waits for a process to terminate and invokes the SIGCHLD handler
  * @param proc pointer to process structure
@@ -467,7 +525,9 @@ open_dev_null (int target_fd,
   fd = open ("/dev/null", flags);
   if (-1 == fd)
   {
   fd = open ("/dev/null", flags);
   if (-1 == fd)
   {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", "/dev/null");
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                             "open",
+                             "/dev/null");
     return;
   }
   if (fd == target_fd)
     return;
   }
   if (fd == target_fd)
@@ -531,23 +591,30 @@ start_process (int pipe_control,
   int fd_stdin_read;
   int fd_stdin_write;
 
   int fd_stdin_read;
   int fd_stdin_write;
 
-  if (GNUNET_SYSERR == GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
+  if (GNUNET_SYSERR ==
+      GNUNET_OS_check_helper_binary (filename, GNUNET_NO, NULL))
     return NULL; /* not executable */
   if (GNUNET_YES == pipe_control)
   {
     struct GNUNET_DISK_PipeHandle *childpipe;
     int dup_childpipe_read_fd = -1;
 
     return NULL; /* not executable */
   if (GNUNET_YES == pipe_control)
   {
     struct GNUNET_DISK_PipeHandle *childpipe;
     int dup_childpipe_read_fd = -1;
 
-    childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_YES, GNUNET_NO);
+    childpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
+                                 GNUNET_YES, GNUNET_NO);
     if (NULL == childpipe)
       return NULL;
     if (NULL == childpipe)
       return NULL;
-    childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_READ);
-    childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe, GNUNET_DISK_PIPE_END_WRITE);
+    childpipe_read = GNUNET_DISK_pipe_detach_end (childpipe,
+                                                 GNUNET_DISK_PIPE_END_READ);
+    childpipe_write = GNUNET_DISK_pipe_detach_end (childpipe,
+                                                  GNUNET_DISK_PIPE_END_WRITE);
     GNUNET_DISK_pipe_close (childpipe);
     GNUNET_DISK_pipe_close (childpipe);
-    if ((NULL == childpipe_read) || (NULL == childpipe_write) ||
-        (GNUNET_OK != GNUNET_DISK_internal_file_handle_ (childpipe_read,
-        &childpipe_read_fd, sizeof (int))) ||
-        (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
+    if ( (NULL == childpipe_read) ||
+        (NULL == childpipe_write) ||
+        (GNUNET_OK !=
+         GNUNET_DISK_internal_file_handle_ (childpipe_read,
+                                            &childpipe_read_fd,
+                                            sizeof (int))) ||
+        (-1 == (dup_childpipe_read_fd = dup (childpipe_read_fd))))
     {
       if (NULL != childpipe_read)
         GNUNET_DISK_file_close (childpipe_read);
     {
       if (NULL != childpipe_read)
         GNUNET_DISK_file_close (childpipe_read);
@@ -1023,7 +1090,10 @@ start_process (int pipe_control,
                                        &lsocks_read, sizeof (HANDLE));
   }
   else
                                        &lsocks_read, sizeof (HANDLE));
   }
   else
+  {
     lsocks_pipe = NULL;
     lsocks_pipe = NULL;
+    lsocks_write_fd = NULL;
+  }
 
   env_off = 0;
   if (GNUNET_YES == pipe_control)
 
   env_off = 0;
   if (GNUNET_YES == pipe_control)
@@ -1161,7 +1231,7 @@ start_process (int pipe_control,
     if (sizeof (count) != wrote)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     if (sizeof (count) != wrote)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 "Failed to write %u count bytes to the child: %u\n",
+                 "Failed to write %u count bytes to the child: %lu\n",
                  sizeof (count), GetLastError ());
       break;
     }
                  sizeof (count), GetLastError ());
       break;
     }
@@ -1172,7 +1242,7 @@ start_process (int pipe_control,
       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
       if (SOCKET_ERROR == WSADuplicateSocketA (lsocks[i], gnunet_proc->pid, &pi))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                   "Failed to duplicate an socket[%llu]: %u\n", i,
+                   "Failed to duplicate an socket[%u]: %lu\n", i,
                    GetLastError ());
         break;
       }
                    GetLastError ());
         break;
       }
@@ -1189,7 +1259,7 @@ start_process (int pipe_control,
       if (sizeof (size) != wrote)
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
       if (sizeof (size) != wrote)
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                   "Failed to write %u size[%llu] bytes to the child: %u\n",
+                   "Failed to write %u size[%u] bytes to the child: %lu\n",
                    sizeof (size), i, GetLastError ());
         break;
       }
                    sizeof (size), i, GetLastError ());
         break;
       }
@@ -1198,7 +1268,7 @@ start_process (int pipe_control,
       if (sizeof (pi) != wrote)
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
       if (sizeof (pi) != wrote)
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                   "Failed to write %u socket[%llu] bytes to the child: %u\n",
+                   "Failed to write %u socket[%u] bytes to the child: %lu\n",
                    sizeof (pi), i, GetLastError ());
         break;
       }
                    sizeof (pi), i, GetLastError ());
         break;
       }
@@ -1518,25 +1588,27 @@ GNUNET_OS_start_process_s (int pipe_control,
 
 
 /**
 
 
 /**
- * Retrieve the status of a process, waiting on him if dead.
+ * Retrieve the status of a process, waiting on it if dead.
  * Nonblocking version.
  *
  * @param proc process ID
  * @param type status type
  * @param code return code/signal number
  * Nonblocking version.
  *
  * @param proc process ID
  * @param type status type
  * @param code return code/signal number
+ * @param options WNOHANG if non-blocking is desired
  * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
  */
  * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
  */
-int
-GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
-                          enum GNUNET_OS_ProcessStatusType *type,
-                          unsigned long *code)
+static int
+process_status (struct GNUNET_OS_Process *proc,
+                enum GNUNET_OS_ProcessStatusType *type,
+                unsigned long *code,
+                int options)
 {
 #ifndef MINGW
   int status;
   int ret;
 
   GNUNET_assert (0 != proc);
 {
 #ifndef MINGW
   int status;
   int ret;
 
   GNUNET_assert (0 != proc);
-  ret = waitpid (proc->pid, &status, WNOHANG);
+  ret = waitpid (proc->pid, &status, options);
   if (ret < 0)
   {
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
   if (ret < 0)
   {
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
@@ -1582,6 +1654,10 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
     *code = 0;
   }
 #else
     *code = 0;
   }
 #else
+#ifndef WNOHANG
+#define WNOHANG  42 /* just a flag for W32, purely internal at this point */
+#endif
+
   HANDLE h;
   DWORD c, error_code, ret;
 
   HANDLE h;
   DWORD c, error_code, ret;
 
@@ -1597,6 +1673,14 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
   if (h == NULL)
     h = GetCurrentProcess ();
 
   if (h == NULL)
     h = GetCurrentProcess ();
 
+  if (WNOHANG != options)
+  {
+    if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
+    {
+      SetErrnoFromWinError (GetLastError ());
+      return GNUNET_SYSERR;
+    }
+  }
   SetLastError (0);
   ret = GetExitCodeProcess (h, &c);
   error_code = GetLastError ();
   SetLastError (0);
   ret = GetExitCodeProcess (h, &c);
   error_code = GetLastError ();
@@ -1620,6 +1704,48 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 }
 
 
 }
 
 
+/**
+ * Retrieve the status of a process, waiting on it if dead.
+ * Nonblocking version.
+ *
+ * @param proc process ID
+ * @param type status type
+ * @param code return code/signal number
+ * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
+ */
+int
+GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
+                          enum GNUNET_OS_ProcessStatusType *type,
+                          unsigned long *code)
+{
+  return process_status (proc,
+                         type,
+                         code,
+                         WNOHANG);
+}
+
+
+/**
+ * Retrieve the status of a process, waiting on it if dead.
+ * Blocking version.
+ *
+ * @param proc pointer to process structure
+ * @param type status type
+ * @param code return code/signal number
+ * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise
+ */
+int
+GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc,
+                               enum GNUNET_OS_ProcessStatusType *type,
+                               unsigned long *code)
+{
+  return process_status (proc,
+                         type,
+                         code,
+                         0);
+}
+
+
 /**
  * Wait for a process to terminate. The return code is discarded.
  * You must not use #GNUNET_OS_process_status() on the same process
 /**
  * Wait for a process to terminate. The return code is discarded.
  * You must not use #GNUNET_OS_process_status() on the same process
@@ -1762,17 +1888,19 @@ cmd_read (void *cls)
 
   cmd->rtask = NULL;
   tc = GNUNET_SCHEDULER_get_task_context ();
 
   cmd->rtask = NULL;
   tc = GNUNET_SCHEDULER_get_task_context ();
-  if (GNUNET_YES != GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, cmd->r))
+  if (GNUNET_YES !=
+      GNUNET_NETWORK_fdset_handle_isset (tc->read_ready,
+                                        cmd->r))
   {
   {
-    /* timeout, shutdown, etc. */
+    /* timeout */
     proc = cmd->proc;
     cmd->proc = NULL;
     proc (cmd->proc_cls, NULL);
     return;
   }
     proc = cmd->proc;
     cmd->proc = NULL;
     proc (cmd->proc_cls, NULL);
     return;
   }
-  ret =
-      GNUNET_DISK_file_read (cmd->r, &cmd->buf[cmd->off],
-                             sizeof (cmd->buf) - cmd->off);
+  ret = GNUNET_DISK_file_read (cmd->r,
+                              &cmd->buf[cmd->off],
+                              sizeof (cmd->buf) - cmd->off);
   if (ret <= 0)
   {
     if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
   if (ret <= 0)
   {
     if ((cmd->off > 0) && (cmd->off < sizeof (cmd->buf)))
@@ -1795,9 +1923,11 @@ cmd_read (void *cls)
     cmd->off -= (end + 1 - cmd->buf);
     end = memchr (cmd->buf, '\n', cmd->off);
   }
     cmd->off -= (end + 1 - cmd->buf);
     end = memchr (cmd->buf, '\n', cmd->off);
   }
-  cmd->rtask =
-      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
-                                      (cmd->timeout), cmd->r, &cmd_read, cmd);
+  cmd->rtask
+    = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining
+                                      (cmd->timeout),
+                                     cmd->r,
+                                     &cmd_read, cmd);
 }
 
 
 }
 
 
@@ -1824,12 +1954,15 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
   struct GNUNET_DISK_PipeHandle *opipe;
   va_list ap;
 
   struct GNUNET_DISK_PipeHandle *opipe;
   va_list ap;
 
-  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
+  opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
+                           GNUNET_NO, GNUNET_YES);
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);
   /* redirect stdout, don't inherit stderr/stdin */
   if (NULL == opipe)
     return NULL;
   va_start (ap, binary);
   /* redirect stdout, don't inherit stderr/stdin */
-  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL, opipe, NULL, binary, ap);
+  eip = GNUNET_OS_start_process_va (GNUNET_NO, 0, NULL,
+                                   opipe, NULL, binary,
+                                   ap);
   va_end (ap);
   if (NULL == eip)
   {
   va_end (ap);
   if (NULL == eip)
   {
@@ -1843,8 +1976,12 @@ GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc,
   cmd->opipe = opipe;
   cmd->proc = proc;
   cmd->proc_cls = proc_cls;
   cmd->opipe = opipe;
   cmd->proc = proc;
   cmd->proc_cls = proc_cls;
-  cmd->r = GNUNET_DISK_pipe_handle (opipe, GNUNET_DISK_PIPE_END_READ);
-  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout, cmd->r, &cmd_read, cmd);
+  cmd->r = GNUNET_DISK_pipe_handle (opipe,
+                                   GNUNET_DISK_PIPE_END_READ);
+  cmd->rtask = GNUNET_SCHEDULER_add_read_file (timeout,
+                                              cmd->r,
+                                              &cmd_read,
+                                              cmd);
   return cmd;
 }
 
   return cmd;
 }