From edbe7000c8c3c77e4e67b2e4b17a71133a579194 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 10 Nov 2010 12:59:14 +0300
Subject: [PATCH 1/2] [W32] Parent->child control pipe

* GNUNET_OS_start_process* () will create a pipe that is inheritable by the child and place its HANDLE into environment variable table to be passed to the child
* GNUNET_SCHEDULER_run () will call a function that will read this variable and start a thread to handle data coming from the pipe
* GNUNET_OS_process_kill () will write control codes into the pipe, wait for the child to die, and use TerminateProcess() on it in case the wait times out
* Extra functions to create GNUNET_DISK_PIPE from existing native handles
* Extra functions (W32-only) for working with environment tables
---
 src/include/gnunet_os_lib.h |   12 ++
 src/util/disk.c             |   90 +++++++++++++
 src/util/disk.h             |    2 +
 src/util/network.c          |   16 ++-
 src/util/os_priority.c      |  297 +++++++++++++++++++++++++++++++++++++-----
 src/util/scheduler.c        |    2 +
 6 files changed, 380 insertions(+), 39 deletions(-)

diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h
index 5ff2b48..6bc6035 100644
--- a/src/include/gnunet_os_lib.h
+++ b/src/include/gnunet_os_lib.h
@@ -273,6 +273,18 @@ int GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
  */
 int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc);
 
+/**
+ * Read env variable and set up the read end of the control
+ * pipe that parent uses to send signals to this process.
+ *
+ * Only does something on Windows
+ *
+ * @param cls user-specified parameter (NULL)
+ * @param tc task context
+ */
+void GNUNET_OS_install_parent_control_handler (void *cls,
+                                               const struct
+                                               GNUNET_SCHEDULER_TaskContext * tc);
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
diff --git a/src/util/disk.c b/src/util/disk.c
index 307c453..1a3b79c 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -1910,4 +1910,94 @@ GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
   return GNUNET_OK;
 }
 
+struct GNUNET_DISK_FileHandle
+GNUNET_DISK_file_from_internal_handle_ (void *src, size_t src_len)
+{
+  struct GNUNET_DISK_FileHandle ret;
+#ifdef MINGW
+  if (src_len == sizeof (HANDLE))
+    ret.h = *(HANDLE *) src;
+  else
+    ret.h = INVALID_HANDLE_VALUE;
+#else
+  if (src_len == sizeof (int))
+    ret.fd = *(int *) src;
+  else
+    ret.fd = -1;
+#endif
+  return ret;
+}
+
+struct GNUNET_DISK_PipeHandle *
+GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len)
+{
+  struct GNUNET_DISK_PipeHandle *p;
+  struct GNUNET_DISK_FileHandle *fds;
+
+  p =
+    GNUNET_malloc (sizeof (struct GNUNET_DISK_PipeHandle) +
+                   2 * sizeof (struct GNUNET_DISK_FileHandle));
+  fds = (struct GNUNET_DISK_FileHandle *) &p[1];
+  p->fd[0] = &fds[0];
+  p->fd[1] = &fds[1];
+  fds[0] = GNUNET_DISK_file_from_internal_handle_ (src0, src_len);
+  fds[1] = GNUNET_DISK_file_from_internal_handle_ (src1, src_len);
+#ifndef MINGW
+  int fd[2];
+  int ret;
+  int flags;
+  int eno;
+
+  fd[0] = fds[0].fd;
+  fd[1] = fds[1].fd;
+  ret = 0;
+  if (fd[0] >= 0)
+  {
+    flags = fcntl (fd[0], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[0], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[0], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[0], F_SETFD, flags))
+      ret = -1;
+  }
+  if (fd[1] >= 0)
+  {
+    flags = fcntl (fd[1], F_GETFL);
+    if (!blocking)
+      flags |= O_NONBLOCK;
+    if (0 > fcntl (fd[1], F_SETFL, flags))
+      ret = -1;
+    flags = fcntl (fd[1], F_GETFD);
+    flags |= FD_CLOEXEC;
+    if (0 > fcntl (fd[1], F_SETFD, flags))
+      ret = -1;
+  }
+  if (ret == -1)
+    {
+      eno = errno;
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fcntl");
+      GNUNET_free (p);
+      errno = eno;
+      return NULL;    
+    }
+#else
+  /* Empirical fact: DuplicateHandle() on a handle inherited from the parent
+   * dies with ERROR_INVALID_HANDLE, so we won't try to duplicate these to
+   * make them inheritable/uninheritable.
+   */
+  if (!blocking)
+  {
+    DWORD mode;
+
+    mode = PIPE_NOWAIT;
+    SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
+    SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
+    /* this always fails on Windows 95, so we don't care about error handling */
+  }
+#endif
+  return p;
+}
 /* end of disk.c */
diff --git a/src/util/disk.h b/src/util/disk.h
index 3d52b9e..5e9647e 100644
--- a/src/util/disk.h
+++ b/src/util/disk.h
@@ -61,5 +61,7 @@ struct GNUNET_DISK_FileHandle
  */ 
 int GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle
                                        *fh, void *dst, size_t dst_len);
+
+struct GNUNET_DISK_PipeHandle *GNUNET_DISK_pipe_from_internal_handles_ (int blocking, void *src0, void *src1, size_t src_len);
 
 #endif  /* GNUNET_DISK_H_ */
diff --git a/src/util/network.c b/src/util/network.c
index 58d67ed..78ff01e 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1138,9 +1138,19 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
             {
               HANDLE h;
-              DWORD dwBytes;
+              DWORD dwBytes = 0, error_code;
+              BOOL bresult;
               h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+              bresult = PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL);
+              error_code = GetLastError ();
+              /* FIXME: This should fail when the pipe is _really_ invalid,
+               * should skip the pipe if the error means that it's
+               * temporarily unavailable, and should succeed if the pipe
+               * is broken (or that the otherwise valid pipe is in a condition
+               * that prevents further reading). 
+               * For now it succeeds only when the pipe is broken or readable.
+               */
+              if (!bresult && error_code != ERROR_BROKEN_PIPE)
                 {
                   retcode = -1;
                   SetErrnoFromWinError (GetLastError ());
@@ -1152,7 +1162,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 #endif
                   goto select_loop_end;
                 }
-              else if (dwBytes)
+              else if (dwBytes || error_code == ERROR_BROKEN_PIPE)
 
                 {
                   GNUNET_CONTAINER_slist_add (handles_read,
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index fb6c292..10beff4 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -29,11 +29,14 @@
 #include "gnunet_os_lib.h"
 #include "disk.h"
 
+#define GNUNET_OS_NT_CONTROL_PIPE "GNUNET_OS_NT_CONTROL_PIPE"
+
 struct GNUNET_OS_Process
 {
   pid_t pid;
 #if WINDOWS
   HANDLE handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe;
 #endif
 };
 
@@ -42,14 +45,81 @@ static struct GNUNET_OS_Process current_process;
 
 #if WINDOWS
 void
-GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
+GNUNET_OS_parent_control_handler (void *cls,
+                                  const struct
+                                  GNUNET_SCHEDULER_TaskContext * tc)
 {
-  if (proc->handle != NULL)
-    CloseHandle (proc->handle);
-  proc->handle = handle;
+  struct GNUNET_DISK_PipeHandle *control_pipe = (struct GNUNET_DISK_PipeHandle *) cls;
+  unsigned char code;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_OS_parent_control_handler is invoked because of %d\n", tc->reason);
+
+  if (tc->reason & (GNUNET_SCHEDULER_REASON_SHUTDOWN | GNUNET_SCHEDULER_REASON_TIMEOUT | GNUNET_SCHEDULER_REASON_PREREQ_DONE))
+  {
+      GNUNET_DISK_pipe_close (control_pipe);
+  }
+  else
+  {
+    if (GNUNET_DISK_file_read (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &code, sizeof (char)) != sizeof (char))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_DISK_file_read have failed, errno = %d. Closing the control pipe.\n", errno);
+      GNUNET_DISK_pipe_close (control_pipe);
+    }
+    else
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got control code %d\n", code);
+      switch (code)
+      {
+        case 0:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGTERM\n");
+          raise (SIGTERM);
+          break;
+        case 1:
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Raising SIGKILL\n");
+          raise (SIGKILL);
+          break;
+        case 255:
+          /* read more bytes - a possibility for extended signals
+           * in case 254 different valies is not enough
+           */
+          break;
+        default:
+          break;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-adding parent control handler pipe to the scheduler\n");
+      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+    }
+  }
 }
 #endif
 
+void
+GNUNET_OS_install_parent_control_handler (void *cls,
+                                          const struct
+                                          GNUNET_SCHEDULER_TaskContext * tc)
+{
+#ifdef WINDOWS
+  char *env_buf;
+  char *endptr;
+  HANDLE control_pipe_end[2];
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+
+  env_buf = getenv (GNUNET_OS_NT_CONTROL_PIPE);
+  if (env_buf == NULL || strlen (env_buf) <= 0 || env_buf[0] < '0' || env_buf[0] > '9')
+    return;
+
+  control_pipe_end[0] = (HANDLE) strtol (env_buf, &endptr, 10);
+  control_pipe_end[1] = INVALID_HANDLE_VALUE;
+ 
+  control_pipe = GNUNET_DISK_pipe_from_internal_handles_ (GNUNET_NO, &control_pipe_end[0], &control_pipe_end[1], sizeof (HANDLE));
+  if (control_pipe == NULL)
+    return;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding parent control handler pipe to the scheduler\n");
+  GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), GNUNET_OS_parent_control_handler, control_pipe);
+#endif
+}
+
 
 /**
  * Get process structure for current process
@@ -66,7 +136,7 @@ GNUNET_OS_process_current ()
   current_process.pid = GetCurrentProcessId ();
   current_process.handle = GetCurrentProcess ();
 #else
-  current_process.pid = 0;
+  current_process.pid = getpid ();
 #endif
   return &current_process;
 }
@@ -75,27 +145,56 @@ int
 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 {
 #if WINDOWS
-  if (sig == SIGKILL || sig == SIGTERM)
+  unsigned char c;
+  DWORD dwresult, error_code = NO_ERROR;
+  BOOL bresult = 1;
+
+  switch (sig)
   {
-    HANDLE h = proc->handle;
-    if (NULL == h)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-		  _("Invalid process information {%d, %08X}\n"),
-		  proc->pid,
-		  h);
-      return -1;
-    }
-    if (!TerminateProcess (h, 0))
-    {
-      SetErrnoFromWinError (GetLastError ());
-      return -1;
+  case SIGKILL:
+    c = 1;
+    break;
+  case SIGTERM:
+    c = 0;
+    break;
+  default:
+    errno = EINVAL;
+    return -1;
+  }
+
+  if (GNUNET_DISK_file_write (
+      GNUNET_DISK_pipe_handle (proc->control_pipe, GNUNET_DISK_PIPE_END_WRITE),
+      &c, sizeof (c)) != sizeof (c))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Failed to write into control pipe, errno is %d\n", errno);
+    bresult = 0;
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Wrote control code into control pipe, now waiting\n");
+    SetLastError (0);
+    dwresult = WaitForSingleObject (proc->handle, 4*1000);
+    error_code = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "Woke up, returned %d, GLE is %d\n", dwresult, error_code);
+    if (WAIT_OBJECT_0 != dwresult || error_code != NO_ERROR)
+    {
+      SetLastError (0);
+      bresult = TerminateProcess (proc->handle, 0);
+      error_code = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+          "TerminateProcess for the child returned %d, GLE is %d\n", bresult,
+          error_code);
     }
-    else
-      return 0;
   }
-  errno = EINVAL;
-  return -1;
+  if (error_code != NO_ERROR || !bresult)
+  {
+    return -1;
+  }
+  else
+    return 0;
 #else
   return kill (proc->pid, sig);
 #endif
@@ -258,6 +357,80 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
   return GNUNET_OK;
 }
 
+#if WINDOWS
+/**
+ * Look through the @env_table and find its size (in bytes, excluding
+ * all NULL-terminators) and item count.
+ *
+ * Use count + size + 1 to calculate the size of the envtable in memory
+ *
+ * @param env_table environment table, as returned by GetEnvironmentStrings()
+ * @param count returned number of elements
+ * @param size returned total length of the items
+ * @return GNUNET_SYSERR on error, GNUNET_OK on success
+ */
+int
+GetEnvTableSizeA (const char *env_table, size_t *count, size_t *size)
+{
+  size_t tablesize = 0;
+  size_t items_count = 0;
+  const char *ptr;
+  if (!env_table)
+    return GNUNET_SYSERR;
+  for (items_count = 0, ptr = win32_env_table; ptr[0] != 0; items_count++)
+  {
+    size_t len = strlen (ptr);
+    tablesize += len;
+    ptr += len + 1;
+  }
+  if (count)
+    *count = items_count;
+  if (size)
+    *size = tablesize;
+  return GNUNET_OK;
+}
+
+char *
+CreateEnvTableA ()
+{
+  char *result = NULL;
+  size_t count, size;
+  const char *win32_env_table;
+  win32_env_table = GetEnvironmentStrings ();
+  if (win32_env_table == NULL || GNUNET_OK != GetEnvTableSizeA (win32_env_table, &count, &size))
+    return NULL;
+  result = GNUNET_malloc (count + size + 1);
+  if (result)
+    memcpy (result, win32_env_table, count + size + 1);
+  if (win32_env_table)
+    FreeEnvironmentStrings (win32_env_table);
+  return result;
+}
+
+char *
+AddToEnvTableA (char *env_table, const char *newvar)
+{
+  char *result = NULL, *ptr;
+  size_t count, size, new_var_size;
+  new_var_size = strlen (newvar);
+  if (env_table == NULL || GNUNET_OK != GetEnvTableSizeA ((const char *) env_table, &count, &size))
+  {
+    GNUNET_free (env_table);
+    return NULL;
+  }
+  result = GNUNET_malloc (count + 1 + size + new_var_size + 1);
+  if (result)
+  {
+    memcpy (result, win32_env_table, count + size);
+    ptr = result + count + size;
+    memcpy (ptr, newvar, new_var_size + 1);
+    ptr[new_var_size + 1] = 0;
+  }
+  GNUNET_free (env_table);
+  return result;
+}
+#endif
+
 /**
  * Start a process.
  *
@@ -368,19 +541,31 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf;
+  char *env_block = NULL;
 
   HANDLE stdin_handle;
   HANDLE stdout_handle;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   char path[MAX_PATH + 1];
 
-  cmdlen = 0;
+  if ((HINSTANCE) 32 >= FindExecutableA (filename, NULL, path)) 
+    {
+      SetErrnoFromWinError (GetLastError ());
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      return NULL;
+    }
+
+  cmdlen = strlen (path) + 3;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       cmdlen = cmdlen + strlen (arg) + 3;
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
+  idx += sprintf (idx, "\"%s\" ", path);
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
       idx += sprintf (idx, "\"%s\" ", arg);
@@ -404,35 +589,47 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
       start.hStdOutput = stdout_handle;
     }
 
-  if (32 >= (int) FindExecutableA (filename, NULL, path)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+  env_block = CreateEnvTableA (env_block);
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
+  GNUNET_free (env_buf);
 
   if (!CreateProcessA
-      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
+      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, env_block, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+
+  if (env_block)
+    GNUNET_free (env_block); 
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
 
   GNUNET_free (cmd);
 
   return gnunet_proc;
 #endif
-
 }
 
 
@@ -557,6 +754,9 @@ GNUNET_OS_start_process_v (const int *lsocks,
   int argcount = 0;
   char non_const_filename[MAX_PATH +1];
   struct GNUNET_OS_Process *gnunet_proc = NULL;
+  struct GNUNET_DISK_PipeHandle *control_pipe = NULL;
+  char *env_buf = NULL, *env_block = NULL;
+  HANDLE control_pipe_read_end, control_pipe_write_end;
 
   GNUNET_assert (lsocks == NULL);
 
@@ -583,7 +783,12 @@ GNUNET_OS_start_process_v (const int *lsocks,
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (argcount == 0)
+        /* Otherwise we'll get the argv[0] without .exe extension,
+           that will break libtool wrapper */
+        non_const_argv[argcount] = GNUNET_strdup (non_const_filename);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -610,22 +815,42 @@ GNUNET_OS_start_process_v (const int *lsocks,
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
-  if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
+  control_pipe = GNUNET_DISK_pipe (GNUNET_NO, 1, 0);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_READ), &control_pipe_read_end, sizeof (HANDLE));
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle (control_pipe, GNUNET_DISK_PIPE_END_WRITE), &control_pipe_write_end, sizeof (HANDLE));
+
+  env_block = CreateEnvTableA (env_block);
+  GNUNET_asprintf (&env_buf, "%s=%d", GNUNET_OS_NT_CONTROL_PIPE, control_pipe_read_end);
+  env_block = AddToEnvTableA (env_block, (const char *) env_buf);
+  GNUNET_free (env_buf);
+
+  if (!CreateProcessA
+      (non_const_filename, cmd, NULL, NULL, TRUE,
+       DETACHED_PROCESS, env_block, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "CreateProcess");
-      return NULL;
+      goto end;
     }
 
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
+  gnunet_proc->control_pipe = control_pipe;
 
   CreateThread (NULL, 64000, ChildWaitThread, (void *) gnunet_proc, 0, NULL);
 
   CloseHandle (proc.hThread);
+end:
+  if (env_block)
+    GNUNET_free (env_block); 
+
+  if (gnunet_proc == NULL)
+    GNUNET_DISK_pipe_close (control_pipe);
+  else
+    GNUNET_DISK_pipe_close_end (control_pipe, GNUNET_DISK_PIPE_END_READ);
+
   GNUNET_free (cmd);
 
   while (argcount > 0)
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 0a4798b..88275e9 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -744,6 +744,8 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
 #endif
   current_priority = GNUNET_SCHEDULER_PRIORITY_DEFAULT;
+  GNUNET_SCHEDULER_add_continuation (GNUNET_OS_install_parent_control_handler,
+				     NULL, GNUNET_SCHEDULER_REASON_STARTUP);
   GNUNET_SCHEDULER_add_continuation (task,
                                      task_cls,
                                      GNUNET_SCHEDULER_REASON_STARTUP);
-- 
1.7.3.1.msysgit.0

