You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2010/01/15 08:49:00 UTC

svn commit: r899551 - in /commons/sandbox/runtime/trunk/src/main/native: include/ include/arch/unix/ include/arch/windows/ os/win32/ test/

Author: mturk
Date: Fri Jan 15 07:49:00 2010
New Revision: 899551

URL: http://svn.apache.org/viewvc?rev=899551&view=rev
Log:
Split process and pipe waits

Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_error.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr_memory.h
    commons/sandbox/runtime/trunk/src/main/native/include/arch/unix/acr_arch.h
    commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
    commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h
    commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/pipe.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c
    commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_error.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_error.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_error.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_error.h Fri Jan 15 07:49:00 2010
@@ -32,8 +32,9 @@
  */
 
 /* Exception throw helper macros */
-#define THROW_FMARK  __FILE__, __LINE__
-#define THROW_NMARK  NULL, 0
+#define THROW_FMARK     __FILE__, __LINE__
+#define THROW_NMARK     NULL, 0
+#define THROW_NEVER     INVALID_JNIENV, NULL, 0
 
 /* Exception class enums */
 typedef enum {

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_exec.h Fri Jan 15 07:49:00 2010
@@ -142,7 +142,19 @@
                                  const acr_pchar_t *const *argv,
                                  acr_pchar_t *const *envp);
 
-ACR_DECLARE(int) ACR_ExecSubproc(acr_exec_t *ep, const acr_pchar_t *executable,
+/**
+ * Execute program via stup
+ * @param exe The executable object
+ * @param stubexe Stub executable. Use NULL for platform default.
+ * @param executable Program to execute
+ * @param argv Parameters for the program.
+ * @param envp Optional environment passed to the program. If null the current
+ *             environment of the calling process is used.
+ * @return Exit reason.
+ */
+ACR_DECLARE(int) ACR_ExecSubproc(acr_exec_t *ep,
+                                 const acr_pchar_t *stubexe,
+                                 const acr_pchar_t *executable,
                                  const acr_pchar_t *const *argv,
                                  acr_pchar_t *const *envp);
 

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_memory.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_memory.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_memory.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_memory.h Fri Jan 15 07:49:00 2010
@@ -38,7 +38,8 @@
 #define ACR_EMALLOC(T, S)       ((T *)ACR_Malloc(_E, THROW_FMARK, (S)))
 #define ACR_ECALLOC(T, S)       ((T *)ACR_Calloc(_E, THROW_FMARK, (S)))
 #define ACR_ARRAY_ALLOC(T, N)   ((T *)ACR_Aalloc(_E, THROW_FMARK, (N)))
-#define ACR_MEMZERO(T, M, N)    memset((M), 0, sizeof((T)) * (N))
+#define ACR_MEMZERO(T, M, N)    memset(M, 0, sizeof(T) * N)
+
 /**
  * This macros supress exceptions on invalid
  * pointers if it's not needed

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/unix/acr_arch.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/unix/acr_arch.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/unix/acr_arch.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/unix/acr_arch.h Fri Jan 15 07:49:00 2010
@@ -58,6 +58,7 @@
 #define IS_INVALID_HANDLE(h) (((h) == NULL || (h) == INVALID_HANDLE_VALUE))
 #define IS_VALID_HANDLE(h)   (((h) != NULL && (h) != INVALID_HANDLE_VALUE))
 
+#define INVALID_JNIENV       ((void *)(ptrdiff_t)-1)
 #define INVALID_MEMORY_VALUE ((void *)(ptrdiff_t)-1)
 #define IS_INVALID_MEMORY(h) (((h) == NULL || (h) == INVALID_MEMORY_VALUE))
 #define IS_VALID_MEMORY(h)   (((h) != NULL && (h) != INVALID_MEMORY_VALUE))

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch.h Fri Jan 15 07:49:00 2010
@@ -896,10 +896,12 @@
 #define IS_INVALID_HANDLE(h) (((h) == NULL || (h) == INVALID_HANDLE_VALUE))
 #define IS_VALID_HANDLE(h)   (((h) != NULL && (h) != INVALID_HANDLE_VALUE))
 
+#define INVALID_JNIENV       ((void *)(ptrdiff_t)-1)
 #define INVALID_MEMORY_VALUE ((void *)(ptrdiff_t)-1)
 #define IS_INVALID_MEMORY(h) (((h) == NULL || (h) == INVALID_MEMORY_VALUE))
 #define IS_VALID_MEMORY(h)   (((h) != NULL && (h) != INVALID_MEMORY_VALUE))
 
+
 #define ACR_REGS_CPU  "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\"
 #define ACR_REGS_CPU0 ACR_REGS_CPU "0\\"
 

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h Fri Jan 15 07:49:00 2010
@@ -155,7 +155,6 @@
     } else (void)0
 
 
-
 void ACR_THREAD_LOCK_EX(void);
 void ACR_THREAD_LOCK_UN(void);
 

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/dir.c Fri Jan 15 07:49:00 2010
@@ -168,7 +168,7 @@
 
     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
     /* Allow access only to owner and Administrators Group */
-    sa.lpSecurityDescriptor = ACR_StdSecurityDescriptor(INVALID_HANDLE_VALUE,
+    sa.lpSecurityDescriptor = ACR_StdSecurityDescriptor(INVALID_JNIENV,
                                                         ACR_DT_FILE, perms);
 
     if (CreateDirectoryW(name, &sa))
@@ -195,7 +195,7 @@
                 if (!(rc = _mkdir1(dir, perms))) {
                     /* Try again, now with parents created
                      */
-                    rc = _mkdir0(name, perms);    
+                    rc = _mkdir0(name, perms);
                 }
             }
         }
@@ -239,7 +239,7 @@
         /* Provide INVALID_HANDLE_VALUE for JNIEnv
          * so that in case of failure, exception doesn't get thrown
          */
-        tmpd = ACR_TempDirMake(INVALID_HANDLE_VALUE, J2W(path), J2W(prefix));
+        tmpd = ACR_TempDirMake(INVALID_JNIENV, J2W(path), J2W(prefix));
         if (!tmpd)
             rc = ACR_GET_OS_ERROR();
     } END_WITH_WPATH(prefix);
@@ -263,7 +263,7 @@
     UNREFERENCED_O;
 
     WITH_ZWPATH(paths) {
-        tmpd = ACR_TempPathGet(INVALID_HANDLE_VALUE, J2W(paths));
+        tmpd = ACR_TempPathGet(INVALID_JNIENV, J2W(paths));
     } END_WITH_WPATH(paths);
     if (tmpd)
         return ACR_NewPathObject(_E, ACR_PATH_ABS, tmpd);

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c Fri Jan 15 07:49:00 2010
@@ -143,9 +143,9 @@
 }
 
 typedef struct OVERLAPPED_BUFFER {
-    char    buff[512];
-    DWORD   stat;
     OVERLAPPED o;
+    DWORD      stat;
+    char       buff[PROC_BUFFER_SIZE];
 } OVERLAPPED_BUFFER;
 
 static int do_exec(acr_exec_t *ep, const wchar_t *cmdline,
@@ -159,10 +159,12 @@
     DWORD  rd, wr;
     DWORD  rc = 0;
     BOOL   rs = FALSE;
+    BOOL   iostat;
     DWORD  exitval;
-    HANDLE pipes[6] = { NULL, NULL, NULL, NULL,  NULL, NULL };
-    HANDLE waith[6] = { NULL, NULL, NULL, NULL,  NULL, NULL };
+    HANDLE pipes[6];
+    HANDLE waith[3];
     DWORD  waitn = 0;
+    DWORD  dwTimeout = INFINITE;
     OVERLAPPED_BUFFER ob[3];
     DWORD  dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
     DWORD  dwPipeFlags;
@@ -171,7 +173,15 @@
     wchar_t    *envb = NULL;
     acr_time_t endat = 0;
 
-    BOOL   iostat;
+    /* Before doing anything zero the stack so we
+     * can safely go to cleanup.
+     */
+    ACR_MEMZERO(HANDLE, pipes, 6);
+    ACR_MEMZERO(HANDLE, waith, 3);
+    ACR_MEMZERO(OVERLAPPED_BUFFER,    ob, 3);
+    ACR_MEMZERO(PROCESS_INFORMATION, &pi, 1);
+    ACR_MEMZERO(STARTUPINFOW,        &si, 1);
+    si.cb = sizeof(si);
 
     ep->exitwhy = ACR_PARENT_ERROR;
     if (argv) {
@@ -191,11 +201,6 @@
             goto cleanup;
         }
     }
-    memset(&pi, 0, sizeof(pi));
-    memset(&si, 0, sizeof(si));
-    si.cb = sizeof(si);
-    for (i = 0; i < 3; i++)
-        memset(&ob[i], 0, sizeof(OVERLAPPED_BUFFER));
 
     /* Sanity check.
      * Daemons have no stream pipes
@@ -207,8 +212,8 @@
         dwCreationFlags |= DETACHED_PROCESS;
         si.dwFlags       = STARTF_USESHOWWINDOW;
         si.wShowWindow   = SW_HIDE;
-
     }
+
     /* Create standard stream pipes
      */
     if (ep->flags & ACR_PROC_HAS_STDIN && ep->data.iov_len) {
@@ -239,7 +244,6 @@
         /* Use same pipes for stderr and stdout
          */
         pipes[PIPE_STDERR_WRS] = pipes[PIPE_STDOUT_WRS];
-        pipes[PIPE_STDERR_RDS] = pipes[PIPE_STDOUT_RDS];
     }
     /* Always use STDHANDLES
      * They are either real handles or handles to NUL device
@@ -269,9 +273,10 @@
     si.hStdInput  = pipes[PIPE_STDINP_RDS];
     si.hStdOutput = pipes[PIPE_STDOUT_WRS];
     si.hStdError  = pipes[PIPE_STDERR_WRS];
-    if (ep->limit.timeout > 0)
+    if (ep->limit.timeout > 0) {
+        dwTimeout = PROC_TIMEOUT_STEP;
         endat = ACR_TimeNow() + ep->limit.timeout;
-
+    }
     if (IS_VALID_HANDLE(ep->usertoken)) {
         /* XXX: for terminal services, handles cannot be
          * inherited across sessions. This process must be created
@@ -344,7 +349,6 @@
     }
     /* Setup wait handles
      */
-    waith[waitn++] = pi.hProcess;
     if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
         ob[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
         waith[waitn++] = ob[0].o.hEvent;
@@ -368,8 +372,16 @@
     /* Sink the console pipes and wait until the child terminates.
      */
     do {
-        DWORD dwTimeout =  ep->limit.timeout > 0 ? PROC_TIMEOUT_STEP : INFINITE;
         DWORD ws;
+        if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+            IS_INVALID_HANDLE(pipes[PIPE_STDOUT_RDS]) &&
+            IS_INVALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+            /* All child pipes are closed.
+             * Bail out
+             */
+            rc = 0;
+            break;
+        }
         /* Wait for some event.
          * Note that overlapped Read and Write will be fired immediately
          * because their events are set on signaled. This usualy means that
@@ -384,14 +396,6 @@
                 rc = ACR_DeliverSignals();
             break;
             case WAIT_OBJECT_1:
-                /* Signal on hProcess is set.
-                 * This means the process exited
-                 */
-                GetExitCodeProcess(pi.hProcess, &exitval);
-                rc = 0;
-                rs = FALSE;
-            break;
-            case WAIT_OBJECT_2:
                 /* Signal on stdout stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
@@ -415,17 +419,22 @@
                     if (iostat && rd != 0) {
                         ob[0].stat = 0;
                         rd = acr_sbuf_bcat(&ep->sout, ob[0].buff, rd);
+                        /* Issue another read */
+                        SetEvent(ob[0].o.hEvent);
                     }
                     else {
                         ob[0].stat = GetLastError();
                         if (ob[0].stat != ERROR_IO_PENDING) {
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+                            ResetEvent(ob[0].o.hEvent);
                         }
                     }
                 }
-                rc = ACR_EINTR;
-            break;
-            case WAIT_OBJECT_3:
+                if (ep->flags & ACR_PROC_HAS_STDOUT) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_2:
                 /* Signal on stderr stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
@@ -449,17 +458,22 @@
                     if (iostat && rd != 0) {
                         ob[1].stat = 0;
                         rd = acr_sbuf_bcat(&ep->serr, ob[1].buff, rd);
+                        /* Issue another read */
+                        SetEvent(ob[1].o.hEvent);
                     }
                     else {
                         ob[1].stat = GetLastError();
                         if (ob[1].stat != ERROR_IO_PENDING) {
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+                            ResetEvent(ob[1].o.hEvent);
                         }
                     }
+                }
+                if (ep->flags & ACR_PROC_HAS_STDERR) {
                     rc = ACR_EINTR;
                     break;
                 }
-            case WAIT_OBJECT_4:
+            case WAIT_OBJECT_3:
                 /* Signal on stdin stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
@@ -488,7 +502,9 @@
                     else {
                         ob[2].stat = GetLastError();
                         if (ob[2].stat != ERROR_IO_PENDING) {
+                            FlushFileBuffers(pipes[PIPE_STDINP_WRS]);
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+                            ResetEvent(ob[1].o.hEvent);
                         }
                     }
                 }
@@ -501,7 +517,39 @@
             default:
                 /* Unexpected result from Wait
                  */
-                rc = ACR_EINVAL;
+                rc = ACR_GET_OS_ERROR();
+            break;
+        }
+    } while (rc == ACR_EINTR);
+
+    do {
+        DWORD ws;
+        /* Wait until child ends
+         */
+        ws = ACR_WaitForObjectOrSignal(pi.hProcess, dwTimeout);
+        switch (ws) {
+            case WAIT_ACRSIGNAL_0:
+                /* Signal event is set.
+                 * Get it's status.
+                 */
+                rc = ACR_DeliverSignals();
+            break;
+            case WAIT_OBJECT_1:
+                /* Operation success */
+                GetExitCodeProcess(pi.hProcess, &exitval);
+                rc = 0;
+                rs = FALSE;
+            break;
+            case WAIT_TIMEOUT:
+                if (ACR_TimeNow() >= endat)
+                    rc = ACR_TIMEUP;
+                else
+                    rc = ACR_EINTR;
+            break;
+            default:
+                /* We got the error while waiting
+                 */
+                rc = ACR_GET_OS_ERROR();
             break;
         }
     } while (rc == ACR_EINTR);

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/file.c Fri Jan 15 07:49:00 2010
@@ -885,7 +885,7 @@
         /* Provide INVALID_HANDLE_VALUE for JNIEnv
          * so that in case of failure, exception doesn't get thrown
          */
-        tmpd = ACR_TempDirMake(INVALID_HANDLE_VALUE, J2W(path), J2W(prefix));
+        tmpd = ACR_TempDirMake(INVALID_JNIENV, J2W(path), J2W(prefix));
         if (!tmpd)
             rc = ACR_GET_OS_ERROR();
     } END_WITH_WPATH(prefix);
@@ -908,7 +908,7 @@
     UNREFERENCED_O;
 
     WITH_ZWPATH(paths) {
-        tmpd = ACR_TempPathGet(INVALID_HANDLE_VALUE, J2W(paths));
+        tmpd = ACR_TempPathGet(INVALID_JNIENV, J2W(paths));
     } END_WITH_WPATH(paths);
     if (tmpd)
         return ACR_NewPathObject(_E, ACR_PATH_ABS, tmpd);

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/pipe.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/pipe.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/pipe.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/pipe.c Fri Jan 15 07:49:00 2010
@@ -239,9 +239,7 @@
     DWORD    dwOpenMode;
     DWORD    dwPipeMode;
 
-    name = pipe_name_from_pid(buff,
-                              GetCurrentProcessId(),
-                              ACR_AtomicInc32(&pipe_id));
+    name = pipe_name_from_pid(buff, GetCurrentProcessId(), 0);
 
     sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
     sa.bInheritHandle       = FALSE;
@@ -346,6 +344,7 @@
     }
 
     return 0;
+
 finally:
     if (IS_VALID_HANDLE(hr))
         CloseHandle(hr);

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c Fri Jan 15 07:49:00 2010
@@ -58,14 +58,18 @@
  * Usage: Rundll32.exe <ShortPath\[lib]acr.dll>,SubprocMainW ...
  */
 
+#define PROC_TIMEOUT_STEP   100
+#define PROC_BUFFER_SIZE    512
 typedef struct OVERLAPPED_BUFFER {
-    char    buff[512];
-    DWORD   stat;
     OVERLAPPED o;
+    DWORD      stat;
+    char       buff[PROC_BUFFER_SIZE];
 } OVERLAPPED_BUFFER;
 
-#define PROC_TIMEOUT_STEP   100
-#define PROC_BUFFER_SIZE    512
+
+#define PIPE_STDINP_RPC     0
+#define PIPE_STDOUT_RPC     1
+#define PIPE_STDERR_RPC     2
 
 #define PIPE_STDINP_RDS     0
 #define PIPE_STDINP_WRS     1
@@ -75,6 +79,12 @@
 #define PIPE_STDERR_WRS     5
 
 extern wchar_t *SHELL_PATH;
+/* Rundll32.exe requires short file format fo a dll name.
+ * This is figured out in our DllMain and we
+ * wish to make sure that some other libacr.dll is not
+ * picked up which might have different ABI.
+ */
+extern wchar_t *dll_dos_modname;
 
  /*
   * Instead in Makefile exports could go here as well
@@ -97,6 +107,7 @@
     DWORD  exitval;
     int    i;
     int    argc;
+    int    ppid = -1;
     wchar_t **args = NULL;
     wchar_t **argv = NULL;
     wchar_t  *cmdline = NULL;
@@ -104,21 +115,31 @@
     int pi_have = 0;
     int po_have = 0;
     int pe_have = 0;
-    const wchar_t  *pi_name = NULL;
-    const wchar_t  *po_name = NULL;
-    const wchar_t  *pe_name = NULL;
+    wchar_t  pi_name[64] = L"";
+    wchar_t  po_name[64] = L"";
+    wchar_t  pe_name[64] = L"";
+    const wchar_t *pfx   = L"\\\\.\\pipe\\";
     HANDLE ppipe[3];
     HANDLE pipes[6];
-    HANDLE waith[6];
+    HANDLE waithandle[6];
     DWORD  waitn    = 0;
-    DWORD  dwChildTimeout;
-    OVERLAPPED_BUFFER ob[3];
+    DWORD  dwTimeout = INFINITE;
+    OVERLAPPED_BUFFER overlap[3];
     char pstdinb[PROC_BUFFER_SIZE];
-    DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
+    DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | DETACHED_PROCESS;
     DWORD dwPipeFlags;
     acr_exec_t child;
     acr_time_t endat = 0;
 
+    ACR_MEMZERO(PROCESS_INFORMATION,   &pi, 1);
+    ACR_MEMZERO(STARTUPINFOW,          &si, 1);
+    ACR_MEMZERO(acr_exec_t,         &child, 1);
+    ACR_MEMZERO(HANDLE,              ppipe, 3);
+    ACR_MEMZERO(HANDLE,              pipes, 6);
+    ACR_MEMZERO(OVERLAPPED_BUFFER, overlap, 3);
+    child.pid = -1;
+    si.cb     = sizeof(si);
+
     if ((rc = ACR_Initialize(NULL))) {
         ACR_DEBUG((THROW_FMARK, "Failed to initialize the ACR error=%d\n", rc));
         goto cleanup;
@@ -144,14 +165,6 @@
         goto cleanup;
     }
 
-    ACR_MEMZERO(HANDLE, ppipe, 3);
-    ACR_MEMZERO(HANDLE, pipes, 6);
-    ACR_MEMZERO(HANDLE, waith, 6);
-    ACR_MEMZERO(OVERLAPPED_BUFFER, ob, 3);
-
-    ACR_MEMZERO(acr_exec_t, &child, 1);
-    child.pid = -1;
-
     for (i = 2; i < argc; i++) {
         if ((argv[i][0] == L'/' && argv[i][1] == L'/') ||
             (argv[i][0] == L'-' && argv[i][1] == L'-')) {
@@ -172,24 +185,44 @@
                 *(opt++) = '\0';
             rc = ACR_EINVAL;
             switch (*cmd) {
+                case L'P':
+                    if (!opt)
+                        goto cleanup;
+                    ppid = _wtoi(opt);
+                break;
                 case L'T':
                     if (!opt)
                         goto cleanup;
                     child.limit.timeout = _wtoi64(opt);
                 break;
                 case L'I':
-                    /* Where the child stdin should be redirected */
-                    pi_name = opt;
+                    /* Where the child stdin should be redirected
+                     * Note that since known we don't pass the \\.\pipe\
+                     * prefix so we need to recreate the full name here.
+                     * XXX: Instead giving names we could pass the pipe id
+                     *      and construct the pipe name. This would lower
+                     *      the size of argument line.
+                     */
+                    if (opt) {
+                        wcslcpy(pi_name, pfx, sizeof(pi_name));
+                        wcslcat(pi_name, opt, sizeof(pi_name));
+                    }
                     child.flags |= ACR_PROC_HAS_STDIN;
                 break;
                 case L'O':
                     /* Where the child stdout should be redirected */
-                    po_name = opt;
+                    if (opt) {
+                        wcslcpy(po_name, pfx, sizeof(po_name));
+                        wcslcat(po_name, opt, sizeof(po_name));
+                    }
                     child.flags |= ACR_PROC_HAS_STDOUT;
                 break;
                 case L'E':
                     /* Where the child stderr should be redirected */
-                    pe_name = opt;
+                    if (opt) {
+                        wcslcpy(pe_name, pfx, sizeof(pe_name));
+                        wcslcat(pe_name, opt, sizeof(pe_name));
+                    }
                     child.flags |= ACR_PROC_HAS_STDERR;
                 break;
                 case L'D':
@@ -222,12 +255,11 @@
     for (i = 0; i < argc; i++) {
         ACR_DEBUG((THROW_FMARK, "ARGV[%d]='%S'\n", i, argv[i]));
     }
-    memset(&pi, 0, sizeof(pi));
-    memset(&si, 0, sizeof(si));
-    si.cb = sizeof(si);
-
-    dwChildTimeout = child.limit.timeout > 0 ? PROC_TIMEOUT_STEP : INFINITE;
 
+    if (child.limit.timeout > 0) {
+        dwTimeout = PROC_TIMEOUT_STEP;
+        endat = ACR_TimeNow() + child.limit.timeout;
+    }
     /* Sanity check.
      * Daemons have no stream pipes
      */
@@ -235,7 +267,8 @@
         child.flags &= ~(ACR_PROC_HAS_STDIN  |
                          ACR_PROC_HAS_STDOUT |
                          ACR_PROC_HAS_STDERR);
-        dwCreationFlags |= DETACHED_PROCESS;
+        /* Start GUI programs as hidden
+         */
         si.dwFlags       = STARTF_USESHOWWINDOW;
         si.wShowWindow   = SW_HIDE;
     }
@@ -248,21 +281,30 @@
         if ((rc = pipepair(&pipes[PIPE_STDINP_RDS], &pipes[PIPE_STDINP_WRS],
                            NULL, ACR_PIPE_READ_BLOCK)))
             goto cleanup;
+
         /* Open the handle to the parent stdin
-         * TODO: We need to create the named pipe here so that
-         *       our parent can connect to us.
+         * We need to create the named pipe here so that
+         * our parent can connect to us.
+         *
+         * This is blocking pipe like all our parent pipes.
          */
-        ppipe[0] = CreateFileW(pi_name,
-                               GENERIC_READ,
-                               0,
-                               &sa,
-                               OPEN_EXISTING,
-                               FILE_ATTRIBUTE_NORMAL,
-                               NULL);
+        ppipe[PIPE_STDINP_RPC] = CreateNamedPipeW(pi_name,
+                                    PIPE_ACCESS_INBOUND,
+                                    0,
+                                    1,
+                                    0,
+                                    65536,
+                                    1,
+                                    &sa);
+
         if (IS_INVALID_HANDLE(ppipe[0])) {
             rc = ACR_GET_OS_ERROR();
             goto cleanup;
         }
+        /* Our parent is already waiting on the pipe
+         */
+
+        ConnectNamedPipe(ppipe[PIPE_STDINP_RPC], NULL);
     }
     else {
         /* Use NUL (aka /dev/null) */
@@ -274,14 +316,14 @@
             goto cleanup;
         /* Open the handle to the parent stdout
          */
-        ppipe[1] = CreateFileW(po_name,
-                               GENERIC_WRITE | FILE_READ_ATTRIBUTES,
-                               0,
-                               &sa,
-                               OPEN_EXISTING,
-                               FILE_ATTRIBUTE_NORMAL,
-                               NULL);
-        if (IS_INVALID_HANDLE(ppipe[1])) {
+        ppipe[PIPE_STDOUT_RPC] = CreateFileW(po_name,
+                                    GENERIC_WRITE,
+                                    0,
+                                    &sa,
+                                    OPEN_EXISTING,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+        if (IS_INVALID_HANDLE(ppipe[PIPE_STDOUT_RPC])) {
             rc = ACR_GET_OS_ERROR();
             goto cleanup;
         }
@@ -296,14 +338,14 @@
             goto cleanup;
         /* Open the handle to the parent stderr
          */
-        ppipe[2] = CreateFileW(pe_name,
-                               GENERIC_WRITE,
-                               0,
-                               &sa,
-                               OPEN_EXISTING,
-                               FILE_ATTRIBUTE_NORMAL,
-                               NULL);
-        if (IS_INVALID_HANDLE(ppipe[2])) {
+        ppipe[PIPE_STDERR_RPC] = CreateFileW(pe_name,
+                                    GENERIC_WRITE,
+                                    0,
+                                    &sa,
+                                    OPEN_EXISTING,
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+        if (IS_INVALID_HANDLE(ppipe[PIPE_STDERR_RPC])) {
             rc = ACR_GET_OS_ERROR();
             goto cleanup;
         }
@@ -312,7 +354,6 @@
         /* Use same pipes for stderr and stdout
          */
         pipes[PIPE_STDERR_WRS] = pipes[PIPE_STDOUT_WRS];
-        pipes[PIPE_STDERR_RDS] = pipes[PIPE_STDOUT_RDS];
     }
 
     /* Always use STDHANDLES
@@ -343,8 +384,6 @@
     si.hStdInput  = pipes[PIPE_STDINP_RDS];
     si.hStdOutput = pipes[PIPE_STDOUT_WRS];
     si.hStdError  = pipes[PIPE_STDERR_WRS];
-    if (child.limit.timeout > 0)
-        endat = ACR_TimeNow() + child.limit.timeout;
 
     rs = CreateProcessW(
             argv[0],            /* Executable */
@@ -378,19 +417,18 @@
     }
     /* Setup wait handles
      */
-    waith[waitn++] = pi.hProcess;
     if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
-        ob[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
-        waith[waitn++] = ob[0].o.hEvent;
+        overlap[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[0].o.hEvent;
     }
     if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS]) &&
         (child.flags & ACR_PROC_HAS_STDERR)) {
-        ob[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
-        waith[waitn++] = ob[1].o.hEvent;
+        overlap[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[1].o.hEvent;
     }
     if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS])) {
-        ob[2].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
-        waith[waitn++] = ob[2].o.hEvent;
+        overlap[2].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[2].o.hEvent;
     }
 
     /* We have created a process with the suspended main thread.
@@ -403,10 +441,19 @@
      */
     do {
         DWORD ws;
-        /* Do some blocking read from the parent
+        if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+            IS_INVALID_HANDLE(pipes[PIPE_STDOUT_RDS]) &&
+            IS_INVALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+            /* All child pipes are closed.
+             * Bail out
+             */
+            rc = 0;
+            break;
+        }
+        /* Do a blocking read from the parent
          */
-        if (IS_VALID_HANDLE(ppipe[0]) && child.data.iov_len == 0) {
-            iostat = ReadFile(ppipe[PIPE_STDOUT_RDS],
+        if (IS_VALID_HANDLE(ppipe[PIPE_STDINP_RPC]) && child.data.iov_len == 0) {
+            iostat = ReadFile(ppipe[PIPE_STDINP_RPC],
                               pstdinb, sizeof(pstdinb),
                               &rd, NULL);
             if (iostat && rd != 0) {
@@ -416,7 +463,10 @@
             else {
                 child.data.iov_len = 0;
                 inpp = NULL;
-                SAFE_CLOSE_HANDLE(ppipe[0]);
+                FlushFileBuffers(pipes[PIPE_STDINP_WRS]);
+                SAFE_CLOSE_HANDLE(ppipe[PIPE_STDINP_RPC]);
+                SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+                ResetEvent(overlap[2].o.hEvent);
             }
         }
         /* Wait for some event.
@@ -424,7 +474,7 @@
          * because their events are set on signaled. This usualy means that
          * the first ReadFile/WriteFile will fail with ERROR_IO_PENDING.
          */
-        ws = ACR_WaitForMultipleObjectOrSignal(waitn, waith, dwChildTimeout);
+        ws = ACR_WaitForMultipleObjectOrSignal(waitn, waithandle, dwTimeout);
         switch (ws) {
             case WAIT_ACRSIGNAL_0:
                 /* Signal event is set.
@@ -433,95 +483,100 @@
                 rc = ACR_DeliverSignals();
             break;
             case WAIT_OBJECT_1:
-                /* Signal on hProcess is set.
-                 * This means the process exited
-                 */
-                GetExitCodeProcess(pi.hProcess, &exitval);
-                rc = 0;
-                rs = FALSE;
-            break;
-            case WAIT_OBJECT_2:
                 /* Signal on stdout stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
-                    if (ob[0].stat == ERROR_IO_PENDING) {
+                    if (overlap[0].stat == ERROR_IO_PENDING) {
                         if (!GetOverlappedResult(pipes[PIPE_STDOUT_RDS],
-                                                 &ob[0].o,
+                                                 &overlap[0].o,
                                                  &rd,
                                                  FALSE)) {
-                            ob[0].stat = GetLastError();
+                            overlap[0].stat = GetLastError();
                         }
                         else {
-                            ob[0].stat = 0;
-                            WriteFile(ppipe[1], ob[0].buff, rd, &wr, NULL);
+                            overlap[0].stat = 0;
+                            WriteFile(ppipe[PIPE_STDOUT_RPC], overlap[0].buff, rd, &wr, NULL);
                         }
                         rc = ACR_EINTR;
                         break;
                     }
                     iostat = ReadFile(pipes[PIPE_STDOUT_RDS],
-                                      ob[0].buff, sizeof(ob[0].buff),
-                                      &rd, &ob[0].o);
+                                      overlap[0].buff, PROC_BUFFER_SIZE,
+                                      &rd, &overlap[0].o);
                     if (iostat && rd != 0) {
-                        ob[0].stat = 0;
-                        WriteFile(ppipe[1], ob[0].buff, rd, &wr, NULL);
+                        overlap[0].stat = 0;
+                        WriteFile(ppipe[PIPE_STDOUT_RPC], overlap[0].buff, rd, &wr, NULL);
+                        /* Issue another read */
+                        SetEvent(overlap[0].o.hEvent);
                     }
                     else {
-                        ob[0].stat = GetLastError();
-                        if (ob[0].stat != ERROR_IO_PENDING) {
+                        overlap[0].stat = GetLastError();
+                        ACR_DEBUG((THROW_FMARK, "RDFAIL STDOUT %d", overlap[0].stat));
+                        if (overlap[0].stat != ERROR_IO_PENDING) {
+                            FlushFileBuffers(ppipe[PIPE_STDOUT_RPC]);
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+                            ResetEvent(overlap[0].o.hEvent);
                         }
                     }
                 }
-                rc = ACR_EINTR;
-            break;
-            case WAIT_OBJECT_3:
-                /* Signal on stderr stream
+                if (child.flags & ACR_PROC_HAS_STDOUT) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_2:
+                /* Signal on stderr or stdin stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
-                    if (ob[1].stat == ERROR_IO_PENDING) {
+                    if (overlap[1].stat == ERROR_IO_PENDING) {
                         if (!GetOverlappedResult(pipes[PIPE_STDERR_RDS],
-                                                 &ob[1].o,
+                                                 &overlap[1].o,
                                                  &rd,
                                                  FALSE)) {
-                            ob[1].stat = GetLastError();
+                            overlap[1].stat = GetLastError();
                         }
                         else {
-                            ob[1].stat = 0;
-                            WriteFile(ppipe[2], ob[1].buff, rd, &wr, NULL);
+                            overlap[1].stat = 0;
+                            WriteFile(ppipe[PIPE_STDERR_RPC], overlap[1].buff, rd, &wr, NULL);
                         }
                         rc = ACR_EINTR;
                         break;
                     }
                     iostat = ReadFile(pipes[PIPE_STDERR_RDS],
-                                      ob[1].buff, sizeof(ob[1].buff),
-                                      &rd, &ob[1].o);
+                                      overlap[1].buff, PROC_BUFFER_SIZE,
+                                      &rd, &overlap[1].o);
                     if (iostat && rd != 0) {
-                        ob[1].stat = 0;
-                        WriteFile(ppipe[2], ob[1].buff, rd, &wr, NULL);
+                        overlap[1].stat = 0;
+                        WriteFile(ppipe[PIPE_STDERR_RPC], overlap[1].buff, rd, &wr, NULL);
+                        /* Issue another read */
+                        SetEvent(overlap[1].o.hEvent);
                     }
                     else {
-                        ob[1].stat = GetLastError();
-                        if (ob[1].stat != ERROR_IO_PENDING) {
+                        overlap[1].stat = GetLastError();
+                        if (overlap[1].stat != ERROR_IO_PENDING) {
+                            FlushFileBuffers(ppipe[PIPE_STDERR_RPC]);
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+                            ResetEvent(overlap[1].o.hEvent);
                         }
                     }
+                }
+                if (child.flags & ACR_PROC_HAS_STDERR) {
                     rc = ACR_EINTR;
                     break;
                 }
-            case WAIT_OBJECT_4:
+            case WAIT_OBJECT_3:
                 /* Signal on stdin stream
                  */
                 if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
                     child.data.iov_len > 0) {
-                    if (ob[2].stat == ERROR_IO_PENDING) {
+                    if (overlap[2].stat == ERROR_IO_PENDING) {
                         if (!GetOverlappedResult(pipes[PIPE_STDINP_WRS],
-                                                 &ob[2].o,
+                                                 &overlap[2].o,
                                                  &wr,
                                                  FALSE)) {
-                            ob[2].stat = GetLastError();
+                            overlap[2].stat = GetLastError();
                         }
                         else {
-                            ob[2].stat = 0;
+                            overlap[2].stat = 0;
                             child.data.iov_len -= wr;
                             inpp               += wr;
                         }
@@ -529,15 +584,17 @@
                         break;
                     }
                     iostat = WriteFile(pipes[PIPE_STDINP_WRS], inpp,
-                                       child.data.iov_len, &wr, &ob[2].o);
+                                       child.data.iov_len, &wr, &overlap[2].o);
                     if (iostat && wr != 0) {
                         child.data.iov_len -= wr;
                         inpp               += wr;
                     }
                     else {
-                        ob[2].stat = GetLastError();
-                        if (ob[2].stat != ERROR_IO_PENDING) {
+                        overlap[2].stat = GetLastError();
+                        if (overlap[2].stat != ERROR_IO_PENDING) {
+                            FlushFileBuffers(pipes[PIPE_STDINP_WRS]);
                             SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+                            ResetEvent(overlap[2].o.hEvent);
                         }
                     }
                 }
@@ -546,15 +603,48 @@
             case WAIT_TIMEOUT:
                 if (ACR_TimeNow() >= endat)
                     rc = ACR_TIMEUP;
+                else
+                    rc = ACR_EINTR;
             break;
             default:
                 /* Unexpected result from Wait
                  */
-                rc = ACR_EINVAL;
+                rc = ACR_GET_OS_ERROR();
             break;
         }
     } while (rc == ACR_EINTR);
 
+    do {
+        DWORD ws;
+        /* Wait until child ends
+         */
+        ws = ACR_WaitForObjectOrSignal(pi.hProcess, dwTimeout);
+        switch (ws) {
+            case WAIT_ACRSIGNAL_0:
+                /* Signal event is set.
+                 * Get it's status.
+                 */
+                rc = ACR_DeliverSignals();
+            break;
+            case WAIT_OBJECT_1:
+                /* Operation success */
+                GetExitCodeProcess(pi.hProcess, &exitval);
+                rc = 0;
+                rs = FALSE;
+            break;
+            case WAIT_TIMEOUT:
+                if (ACR_TimeNow() >= endat)
+                    rc = ACR_TIMEUP;
+                else
+                    rc = ACR_EINTR;
+            break;
+            default:
+                /* We got the error while waiting
+                 */
+                rc = ACR_GET_OS_ERROR();
+            break;
+        }
+    } while (rc == ACR_EINTR);
 
     if (rs) {
         /* Still running.
@@ -579,9 +669,507 @@
     for (i = 0; i < 3; i++)
         SAFE_CLOSE_HANDLE(ppipe[i]);
     for (i = 0; i < 3; i++) {
-        SAFE_CLOSE_HANDLE(ob[i].o.hEvent);
+        SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
     }
     x_free(cmdline);
     ACR_ARRAY_FREE(args);
     ExitProcess(rc);
 }
+
+/* This is parent code for executing the SubprocMain
+ *
+ */
+
+ACR_DECLARE(int) ACR_ExecSubproc(acr_exec_t *ep,
+                                 const wchar_t *stubexe,
+                                 const wchar_t *executable,
+                                 const wchar_t *const *argv,
+                                 wchar_t *const *envp)
+{
+    PROCESS_INFORMATION pi;
+    STARTUPINFOW        si;
+    int i;
+    DWORD    rd, wr;
+    DWORD    rc = 0;
+    BOOL     rs = FALSE;
+    BOOL     iostat;
+    DWORD    exitval;
+    wchar_t *subproc = NULL;
+    wchar_t *stubdll = NULL;
+    wchar_t *sysroot;
+    wchar_t *childpname[3] = { NULL, NULL, NULL };
+    HANDLE   childpipes[3] = { NULL, NULL, NULL };
+    HANDLE   waithandle[4];
+    DWORD    waitn = 0;
+    DWORD    dwTimeout = INFINITE;
+    wchar_t *suba[8] = { NULL, NULL };
+    wchar_t     subn = 2;
+    wchar_t   **ccaa = NULL;
+    wchar_t    *args = NULL;
+    wchar_t    *envb = NULL;
+    const char *inpp = NULL;
+    OVERLAPPED_BUFFER overlap[3];
+    DWORD  dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
+    acr_time_t endat = 0;
+
+    ACR_MEMZERO(PROCESS_INFORMATION,   &pi, 1);
+    ACR_MEMZERO(STARTUPINFOW,          &si, 1);
+    ACR_MEMZERO(OVERLAPPED_BUFFER, overlap, 3);
+
+    si.cb = sizeof(si);
+
+    /* Sanity check.
+     * Daemons have no stream pipes
+     */
+    if (ep->flags & ACR_PROC_DETACHED) {
+        ep->flags &= ~(ACR_PROC_HAS_STDIN  |
+                       ACR_PROC_HAS_STDOUT |
+                       ACR_PROC_HAS_STDERR);
+        dwCreationFlags |= DETACHED_PROCESS;
+    }
+    else
+        dwCreationFlags |= CREATE_NO_WINDOW;
+
+    ep->exitwhy = ACR_PARENT_ERROR;
+    if (!(sysroot = acr_EnvGetW(L"SystemRoot"))) {
+        rc = ACR_ENOENT;
+        goto cleanup;
+    }
+
+    if (stubexe)
+        suba[0] = x_wcsdup(stubexe);
+    else
+        suba[0] = ACR_StrvcatW(THROW_NEVER,
+                               sysroot, L"\\System32\\RUNDLL32.EXE", NULL);
+    if (suba[0] == NULL) {
+        rc = ACR_ENOMEM;
+        goto cleanup;
+    }
+    suba[1] = ACR_StrvcatW(THROW_NEVER, NULL,
+                           dll_dos_modname, L",SubprocMainW", NULL);
+    /* Add our pid to the child arguments */
+    suba[subn] = s_malloc(wchar_t, 32);
+    _snwprintf(suba[subn++], 32, L"--P:%d", GetCurrentProcessId());
+    if (ep->limit.timeout > 0) {
+        /* Add Timeout only if set */
+        suba[subn] = s_malloc(wchar_t, 32);
+        _snwprintf(suba[subn++], 32, L"--T:%I64d",ep->limit.timeout);
+    }
+
+    if (ep->limit.timeout > 0) {
+        /* Setup the target timeout */
+        endat = ACR_TimeNow() + ep->limit.timeout;
+    }
+    if (ep->flags & ACR_PROC_HAS_STDIN && ep->data.iov_len) {
+        /* Obtain the name for the stdin pipe
+         * The pipe will be created inside stub.
+         */
+        if ((rc = pipepair(NULL,
+                           NULL,
+                           &childpname[PIPE_STDINP_RPC],
+                           0)))
+            goto cleanup;
+        suba[subn] = s_malloc(wchar_t, 64);
+        _snwprintf(suba[subn++], 64, L"--I:%s", childpname[PIPE_STDINP_RPC] + 9);
+    }
+    if (ep->flags & ACR_PROC_HAS_STDOUT) {
+        if ((rc = pipepair(&childpipes[PIPE_STDOUT_RPC],
+                           NULL,
+                           &childpname[PIPE_STDOUT_RPC],
+                           ACR_PIPE_WRITE_BLOCK)))
+            goto cleanup;
+        suba[subn] = s_malloc(wchar_t, 64);
+        _snwprintf(suba[subn++], 64, L"--O:%s", childpname[PIPE_STDOUT_RPC] + 9);
+    }
+    if (ep->flags & ACR_PROC_HAS_STDERR) {
+        if ((rc = pipepair(&childpipes[PIPE_STDERR_RPC],
+                           NULL,
+                           &childpname[PIPE_STDERR_RPC],
+                           ACR_PIPE_WRITE_BLOCK)))
+            goto cleanup;
+        suba[subn] = s_malloc(wchar_t, 64);
+        _snwprintf(suba[subn++], 64, L"--E:%s", childpname[PIPE_STDERR_RPC] + 9);
+    }
+    suba[subn++] = x_wcsdup(executable);
+    suba[subn] = NULL;
+    /* Merge the new array with the provided arguments
+     */
+    if (!(ccaa = ACR_MergeArgsW(suba, argv))) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    args = ACR_ArgsToStringW(ccaa);
+    if (!args) {
+        rc = ACR_ENOMEM;
+        goto cleanup;
+    }
+    if (envp) {
+        /* Environmet is supposed to be sorted
+         */
+        ACR_ArgsSortW(&envp);
+        envb = ACR_ArrayToMszStrW(envp);
+        if (!envb) {
+            rc = ACR_ENOMEM;
+            goto cleanup;
+        }
+    }
+    if (IS_VALID_HANDLE(ep->usertoken)) {
+        /* XXX: for terminal services, handles cannot be
+         * inherited across sessions. This process must be created
+         * in our existing session. lpDesktop assignment appears
+         * to be wrong according to these rules.
+         */
+        si.lpDesktop = L"Winsta0\\Default";
+        if (!ImpersonateLoggedOnUser(ep->usertoken)) {
+            /* failed to impersonate the logged user */
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+        rs = CreateProcessAsUserW(
+                ep->usertoken,
+                ccaa[0],            /* Executable */
+                args,               /* Command line */
+                NULL,
+                NULL,               /* Proc & thread security attributes */
+                TRUE,               /* Inherit handles */
+                dwCreationFlags,    /* Creation flags */
+                envb,               /* Environment block */
+                ep->currdir,        /* Current directory name */
+                &si,
+                &pi);
+        if (!rs)
+            rc = GetLastError();
+        RevertToSelf();
+    }
+    else {
+        rs = CreateProcessW(
+                ccaa[0],            /* Executable */
+                args,               /* Command line */
+                NULL,
+                NULL,               /* Proc & thread security attributes */
+                TRUE,               /* Inherit handles */
+                dwCreationFlags,    /* Creation flags */
+                envb,               /* Environment block */
+                ep->currdir,        /* Current directory name */
+                &si,
+                &pi);
+        if (!rs)
+            rc = GetLastError();
+    }
+    if (!rs) {
+        /* Child failed. */
+        goto cleanup;
+    }
+    ep->pid = pi.dwProcessId;
+    if (ep->flags & ACR_PROC_DETACHED) {
+        /* We are done in case of detached process
+         */
+        rc = 0;
+        ep->exitwhy = ACR_CHILD_NOTDONE;
+        ResumeThread(pi.hThread);
+        goto finally;
+    }
+
+    if (IS_VALID_HANDLE(childpipes[PIPE_STDOUT_RPC])) {
+        overlap[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[0].o.hEvent;
+        /* Kick the connect event.
+         * This is needed becuase CreateFile is done from different
+         * process.
+         * TODO: Check for the return value
+         */
+        ConnectNamedPipe(childpipes[PIPE_STDOUT_RPC], &overlap[0].o);
+    }
+    if (IS_VALID_HANDLE(childpipes[PIPE_STDERR_RPC])) {
+        overlap[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[1].o.hEvent;
+        /* Kick the connect event */
+        ConnectNamedPipe(childpipes[PIPE_STDERR_RPC], &overlap[1].o);
+    }
+
+    /* We have created a process with the suspended main thread.
+     * Resume the main process thread.
+     */
+    ResumeThread(pi.hThread);
+
+    /* Time to connect to the child's stdin
+     */
+    if ((ep->flags & ACR_PROC_HAS_STDIN) && ep->data.iov_len) {
+        SECURITY_ATTRIBUTES sa;
+        sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+        sa.bInheritHandle       = FALSE;
+        sa.lpSecurityDescriptor = NULL;
+
+        /* XXX: How much should we wait for a stub to create a pipe?
+         *      We cannot wait forever because if the stub deadlocks we'll
+         *      be locked as well.
+         *      For now wait 2 seconds.
+         */
+        if (endat == 0)
+            endat = ACR_TimeNow() + (2 * ACR_USEC_PER_SEC);
+        do {
+            if (!WaitNamedPipeW(childpname[PIPE_STDINP_RPC], 0)) {
+               /* Wait until child ends
+                */
+                rc = ACR_WaitForObjectOrSignal(pi.hProcess, PROC_TIMEOUT_STEP);
+                if (rc != WAIT_TIMEOUT) {
+                    if (rc == WAIT_OBJECT_0) {
+                        /* Child already ended
+                         */
+                        GetExitCodeProcess(pi.hProcess, &exitval);
+                        rc = exitval;
+                        ep->exitwhy = ACR_CHILD_DONE;
+                        goto finally;
+                    }
+                    else
+                        break;
+                }
+            }
+            else
+                break;
+        } while (ACR_TimeNow() >= endat);
+
+        childpipes[PIPE_STDINP_RPC] = CreateFileW(childpname[PIPE_STDINP_RPC],
+                               GENERIC_WRITE,
+                               0,
+                               &sa,
+                               OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+                               NULL);
+        if (IS_INVALID_HANDLE(childpipes[PIPE_STDINP_RPC])) {
+            rc = ACR_GET_OS_ERROR();
+            TerminateProcess(pi.hProcess, 9);
+            ep->exitwhy = ACR_CHILD_SIGNAL;
+
+            goto finally;
+        }
+        overlap[2].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[2].o.hEvent;
+        inpp = (const char *)ep->data.iov_base;
+        ACR_DEBUG((THROW_FMARK, "Has stdin %d", ep->data.iov_len));
+
+    }
+
+    rc = 0;
+    /* Sink the console pipes and wait until the child terminates.
+     */
+    do {
+        DWORD ws;
+
+        if (IS_INVALID_HANDLE(childpipes[PIPE_STDINP_RPC]) &&
+            IS_INVALID_HANDLE(childpipes[PIPE_STDOUT_RPC]) &&
+            IS_INVALID_HANDLE(childpipes[PIPE_STDERR_RPC])) {
+            rc = 0;
+            break;
+        }
+
+        /* Wait for some event.
+         * Note that overlapped Read and Write will be fired immediately
+         * because their events are set on signaled. This usualy means that
+         * the first ReadFile/WriteFile will fail with ERROR_IO_PENDING.
+         */
+        ws = ACR_WaitForMultipleObjectOrSignal(waitn, waithandle, dwTimeout);
+        switch (ws) {
+            case WAIT_ACRSIGNAL_0:
+                /* Signal event is set.
+                 * Get it's status.
+                 */
+                rc = ACR_DeliverSignals();
+            break;
+            case WAIT_OBJECT_1:
+                /* Signal on stdout stream
+                 */
+                if (IS_VALID_HANDLE(childpipes[PIPE_STDOUT_RPC])) {
+                    if (overlap[0].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(childpipes[PIPE_STDOUT_RPC],
+                                                 &overlap[0].o,
+                                                 &rd,
+                                                 FALSE)) {
+                            overlap[0].stat = GetLastError();
+                        }
+                        else {
+                            overlap[0].stat = 0;
+                            rd = acr_sbuf_bcat(&ep->sout, overlap[0].buff, rd);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(childpipes[PIPE_STDOUT_RPC],
+                                      overlap[0].buff, PROC_BUFFER_SIZE,
+                                      &rd, &overlap[0].o);
+                    if (iostat && rd != 0) {
+                        overlap[0].stat = 0;
+                        rd = acr_sbuf_bcat(&ep->sout, overlap[0].buff, rd);
+                        SetEvent(overlap[1].o.hEvent);
+                    }
+                    else {
+                        overlap[0].stat = GetLastError();
+                        if (overlap[0].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(childpipes[PIPE_STDOUT_RPC]);
+                            ResetEvent(overlap[0].o.hEvent);
+                        }
+                    }
+                }
+                if (ep->flags & ACR_PROC_HAS_STDOUT) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            break;
+            case WAIT_OBJECT_2:
+                /* Signal on stdout stream
+                 */
+                if (IS_VALID_HANDLE(childpipes[PIPE_STDERR_RPC])) {
+                    if (overlap[1].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(childpipes[PIPE_STDERR_RPC],
+                                                 &overlap[1].o,
+                                                 &rd,
+                                                 FALSE)) {
+                            overlap[1].stat = GetLastError();
+                        }
+                        else {
+                            overlap[1].stat = 0;
+                            rd = acr_sbuf_bcat(&ep->serr, overlap[1].buff, rd);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(childpipes[PIPE_STDERR_RPC],
+                                      overlap[1].buff, PROC_BUFFER_SIZE,
+                                      &rd, &overlap[1].o);
+                    if (iostat && rd != 0) {
+                        overlap[1].stat = 0;
+                        rd = acr_sbuf_bcat(&ep->sout, overlap[1].buff, rd);
+                        SetEvent(overlap[1].o.hEvent);
+                    }
+                    else {
+                        overlap[1].stat = GetLastError();
+                        if (overlap[1].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(childpipes[PIPE_STDERR_RPC]);
+                            ResetEvent(overlap[1].o.hEvent);
+                        }
+                    }
+                }
+                if (ep->flags & ACR_PROC_HAS_STDERR) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_3:
+                /* Signal on stdin stream
+                 */
+                if (IS_VALID_HANDLE(childpipes[PIPE_STDINP_RPC]) &&
+                    ep->data.iov_len > 0) {
+                    if (overlap[2].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(childpipes[PIPE_STDINP_RPC],
+                                                 &overlap[2].o,
+                                                 &wr,
+                                                 FALSE)) {
+                            overlap[2].stat = GetLastError();
+                        }
+                        else {
+                            overlap[2].stat = 0;
+                            ep->data.iov_len -= wr;
+                            inpp             += wr;
+                            if (ep->data.iov_len == 0) {
+                                FlushFileBuffers(childpipes[PIPE_STDINP_RPC]);
+                                SAFE_CLOSE_HANDLE(childpipes[PIPE_STDINP_RPC]);
+                                ResetEvent(overlap[2].o.hEvent);
+                            }
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = WriteFile(childpipes[PIPE_STDINP_RPC], inpp,
+                                       ep->data.iov_len, &wr, &overlap[2].o);
+                    ACR_DEBUG((THROW_FMARK, "Written %d", wr));
+                    if (iostat && wr != 0) {
+                        ep->data.iov_len -= wr;
+                        inpp             += wr;
+                        if (ep->data.iov_len == 0) {
+                            FlushFileBuffers(childpipes[PIPE_STDINP_RPC]);
+                            SAFE_CLOSE_HANDLE(childpipes[PIPE_STDINP_RPC]);
+                            ResetEvent(overlap[2].o.hEvent);
+                        }
+                    }
+                    else {
+                        overlap[2].stat = GetLastError();
+                        if (overlap[2].stat != ERROR_IO_PENDING) {
+                            FlushFileBuffers(childpipes[PIPE_STDINP_RPC]);
+                            SAFE_CLOSE_HANDLE(childpipes[PIPE_STDINP_RPC]);
+                            ResetEvent(overlap[2].o.hEvent);
+                        }
+                    }
+                }
+                rc = ACR_EINTR;
+            break;
+            default:
+                /* Unexpected result from Wait
+                 */
+                rc = ACR_GET_OS_ERROR();
+            break;
+        }
+    } while (rc == ACR_EINTR);
+
+    do {
+        DWORD ws;
+        /* Wait until child ends
+         */
+        ws = ACR_WaitForObjectOrSignal(pi.hProcess, dwTimeout);
+        switch (ws) {
+            case WAIT_ACRSIGNAL_0:
+                /* Signal event is set.
+                 * Get it's status.
+                 */
+                rc = ACR_DeliverSignals();
+            break;
+            case WAIT_OBJECT_1:
+                /* Operation success */
+                GetExitCodeProcess(pi.hProcess, &exitval);
+                rc = 0;
+                rs = FALSE;
+            break;
+            default:
+                /* We got the error while waiting
+                 */
+                rc = ACR_GET_OS_ERROR();
+            break;
+        }
+    } while (rc == ACR_EINTR);
+
+    if (rs) {
+        /* Still running.
+         * Time to kill the bugger
+         */
+        TerminateProcess(pi.hProcess, 9);
+        ep->exitwhy = ACR_CHILD_SIGNAL;
+        rc = 9;
+    }
+    else {
+        ep->exitwhy = ACR_CHILD_DONE;
+        rc = exitval;
+    }
+
+
+finally:
+    SAFE_CLOSE_HANDLE(pi.hThread);
+    SAFE_CLOSE_HANDLE(pi.hProcess);
+
+cleanup:
+    acr_sbuf_finish(&ep->sout);
+    acr_sbuf_finish(&ep->serr);
+    ep->exitval = rc;
+    for (i = 0; i < subn; i++)
+        x_free(suba[i]);
+    for (i = 0; i < 3; i++)
+        x_free(childpname[i]);
+    for (i = 0; i < 3; i++) {
+        SAFE_CLOSE_HANDLE(childpipes[i]);
+    }
+    for (i = 0; i < 3; i++) {
+        SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
+    }
+    x_free(args);
+    x_free(envb);
+    x_free(ccaa);
+
+    return rc;
+}

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/wutil.c Fri Jan 15 07:49:00 2010
@@ -17,6 +17,7 @@
 #define ACR_WANT_LATE_DLL
 #include "acr.h"
 #include "acr_private.h"
+#include "acr_atomics.h"
 #include "acr_clazz.h"
 #include "acr_error.h"
 #include "acr_memory.h"
@@ -102,6 +103,8 @@
     return rname;
 }
 
+static acr_atomic32_t resource_id = 0;
+
 /**
  * Common pipe resource name
  * MD5 in UUID form of pid and id (see the code).
@@ -111,6 +114,8 @@
     DWORD   rc = 0;
     wchar_t pname[64];
 
+    if (id == 0)
+        id = ACR_AtomicInc32(&resource_id);
     wcscpy(rname, L"\\\\.\\pipe\\");
     _snwprintf(pname, sizeof(pname),
                L"apache-commons-pipe-%08x-%08x", pid, id);

Modified: commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c?rev=899551&r1=899550&r2=899551&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c Fri Jan 15 07:49:00 2010
@@ -65,7 +65,6 @@
 #define _TXT(X)       X
 #endif
 
-
 static int tests_failed = 0;
 
 static acr_getopt_option_t toptions[] = {
@@ -680,15 +679,18 @@
 static int test_exec5(int argc, const char *const argv[])
 {
     int rc;
+    static const char *hello = "Hello world\n";
     acr_exec_t *exe;
+    
     if (argc < 1) {
         return ACR_EINVAL;
     }
-    exe = ACR_ExecNew(ACR_PROC_HAS_STDOUT | ACR_PROC_HAS_STDERR);
+    exe = ACR_ExecNew(ACR_PROC_HAS_STDOUT | ACR_PROC_HAS_STDERR | ACR_PROC_HAS_STDIN);
+    ACR_ExecStdinSet(exe, hello, strlen(hello));
 #if defined(WIN32)
-    rc = ACR_ExecSubproc(exe, wargv[0], &wargv[1], NULL);
+    rc = ACR_ExecSubproc(exe, NULL, wargv[0], &wargv[1], NULL);
 #else
-    rc = ACR_ExecSubproc(exe, argv[0], &argv[1], NULL);
+    rc = ACR_ExecSubproc(exe, NULL, argv[0], &argv[1], NULL);
 #endif
     fprintf(stdout, "[STDOUT]:\n%s", ACR_ExecStream(exe, 1));
     fprintf(stdout, "[STDERR]:\n%s", ACR_ExecStream(exe, 2));