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 2011/04/28 15:22:15 UTC

svn commit: r1097447 - in /commons/sandbox/runtime/trunk/src/main: java/org/apache/commons/runtime/platform/windows/ native/include/acr/ native/os/win32/ test/org/apache/commons/runtime/

Author: mturk
Date: Thu Apr 28 13:22:14 2011
New Revision: 1097447

URL: http://svn.apache.org/viewvc?rev=1097447&view=rev
Log:
Implement initial win32 Exec

Modified:
    commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java
    commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
    commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h
    commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c
    commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java

Modified: commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java (original)
+++ commons/sandbox/runtime/trunk/src/main/java/org/apache/commons/runtime/platform/windows/WindowsExec.java Thu Apr 28 13:22:14 2011
@@ -20,6 +20,10 @@ import org.apache.commons.runtime.Errno;
 import org.apache.commons.runtime.Status;
 import org.apache.commons.runtime.InvalidArgumentException;
 import org.apache.commons.runtime.SystemException;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
+import java.io.OutputStream;
+import java.util.List;
 
 /**
  * WindowsExec class.
@@ -35,5 +39,65 @@ final class WindowsExec extends Exec
     {
 
     }
+    private static native long run0(String executable,
+                                    String cmdline,
+                                    char[] envb,
+                                    String cwd,
+                                    byte[] inp,
+                                    ByteArrayOutputStream out,
+                                    ByteArrayOutputStream err,
+                                    int timeout);
+    public int run(List<String> argv)
+    {
+        String executable = null;
+        StringBuffer args = new StringBuffer();
+
+        for (String s : argv) {
+            if (executable == null) {
+                executable = s;
+                // TODO: Check for both SPACE and TAB
+                //       Make sure quotes are properly handled.
+                if (executable.indexOf(' ') != -1) {
+                    args.append('"');
+                    args.append(executable);
+                    args.append('"');
+                }
+                else
+                    args.append(executable);
+            }
+            else {
+                args.append(' ');
+                if (s.indexOf(' ') != -1) {
+                    args.append('"');
+                    args.append(s);
+                    args.append('"');
+                }
+                else
+                    args.append(s);
+            }
+        }
+        if (executable == null) {
+            return Status.PARENT_ERROR;
+        }
+        char [] envb = null;
+        if (env != null) {
+            CharArrayWriter ew = new CharArrayWriter();
+            for (int i = 0; i < env.length; i++) {
+                try {
+                    ew.write(env[i]);
+                    ew.append('\0');
+                } catch (Exception x) {
+                    //TODO: Handle OOM errors    
+                }
+            }
+            ew.append('\0');
+            envb = ew.toCharArray();
+        }
+        long rv = run0(executable, args.toString(), envb, cwd, inp, out, err, timeout);
+        exitval = (int)(rv & 0xffffffffL);
+        int res = (int)(rv >>> 32);
+
+        return res;
+    }
 
 }

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr/iodefs.h Thu Apr 28 13:22:14 2011
@@ -29,5 +29,10 @@
 #define ACR_PIPE_MODE_MASK      0x000F
 #define ACR_PIPE_NOINHERIT      0x0010
 
+#define ACR_FOPEN_RDONLY     0x000000  /**< Open the file for reading */
+#define ACR_FOPEN_WRITE      0x000001  /**< Open the file for writing */
+#define ACR_FOPEN_RW         0x000002  /**< Convenience for READ | WRITE */
+#define ACR_FOPEN_NOINHERIT  0x010000  /**< Do not inherit files on exec */
+#define ACR_FOPEN_INFO       0x020000  /**< Open without READ or WRITE access */
 
 #endif /* _ACR_IODEFS_H */

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/arch_opts.h Thu Apr 28 13:22:14 2011
@@ -233,4 +233,7 @@ ACR_INLINE(void) MsecTimeToFileTime(LPFI
     return;
 }
 
+HANDLE  AcrNullPipe(int flags, int fd);
+int     AcrPipePair(HANDLE *rd, HANDLE *wr, int flags, char *name);
+
 #endif /* _ACR_ARCH_OPTS_H_ */

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=1097447&r1=1097446&r2=1097447&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 Thu Apr 28 13:22:14 2011
@@ -27,22 +27,17 @@
 #define PROC_TIMEOUT_STEP   100
 #define PROC_BUFFER_SIZE    512
 
-#define PIPE_STDINP         0
 #define PIPE_STDINP_RDS     0
 #define PIPE_STDINP_WRS     1
-#define PIPE_STDOUT         2
 #define PIPE_STDOUT_RDS     2
 #define PIPE_STDOUT_WRS     3
-#define PIPE_STDERR         4
 #define PIPE_STDERR_RDS     4
 #define PIPE_STDERR_WRS     5
-#define PIPE_SIGERR         6
-#define PIPE_SIGERR_RDS     6
-#define PIPE_SIGERR_WRS     7
-#define PIPE_SIGPID         8
-#define PIPE_SIGPID_RDS     8
-#define PIPE_SIGPID_WRS     9
-#define PIPE_COUNT         10
+#define PIPE_COUNT          6
+#define SIGKILL             9
+
+static CRITICAL_SECTION _procmgr_lock;
+static wchar_t         *SHELL_PATH;
 
 J_DECLARE_CLAZZ = {
     INVALID_FIELD_OFFSET,
@@ -58,10 +53,27 @@ J_DECLARE_M_ID(0000) = {
     "()V"
 };
 
+static int _procmgr_init(void)
+{
+    InitializeCriticalSection(&_procmgr_lock);
+
+    SHELL_PATH = _wgetenv(L"COMSPEC");
+    if (SHELL_PATH == 0) {
+        wchar_t b[PATH_MAX];
+        UINT r;
+        r = GetSystemDirectoryW(b, PATH_MAX - 10);
+        if (r == 0 || r > (PATH_MAX - 10))
+            wcscpy(b, L"C:\\Windows\\System32\\cmd.exe");
+        else
+            wcscat(b, L"\\cmd.exe");
+        SHELL_PATH = wcsdup(b);
+    }
+    return 0;
+}
 
 static int _run_exec(const wchar_t *executable,
-                     const wchar_t *cmdline,
-                     const wchar_t *envb,
+                     wchar_t *argb,
+                     wchar_t *envb,
                      const wchar_t *workdir,
                      acr_buf_t *out,
                      acr_buf_t *err,
@@ -69,6 +81,436 @@ static int _run_exec(const wchar_t *exec
                      int timeout,
                      int *retval)
 {
+    PROCESS_INFORMATION pi;
+    STARTUPINFOW        si;
+    BOOL   rs;
+    int    i, rc   = 0;
+    int    exitwhy = 0;
+    int    exitval = 0;
+    HANDLE pipes[PIPE_COUNT] = { 0, 0, 0, 0, 0, 0 };
+    HANDLE waithandle[3]     = { 0, 0, 0 };
+    HANDLE stdhandles[3]     = { 0, 0, 0 };
+    DWORD  stdhinfo[3]       = { 0, 0, 0 };
+    OVERLAPPED_SBUFF overlap[3];
+    HANDLE cproc = GetCurrentProcess();
+    int    sigerr = 0;
+    int    detach = 0;
+    DWORD  waitn  = 0;
+    DWORD  cflags = CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED;
+    DWORD  dflags;
+    DWORD  polltime = INFINITE;
+    int    pid;
+    acr_time_t endat = 0;
+    acr_sb_t   obuf_s;
+    acr_sb_t   ebuf_s;
+    acr_sb_t  *obuf = 0;
+    acr_sb_t  *ebuf = 0;
+    acr_buf_t  ibuf = { 0, 0, 0, 0};
+
+    ACR_MEMZERO(PROCESS_INFORMATION,  &pi, 1);
+    ACR_MEMZERO(STARTUPINFOW,         &si, 1);
+    ACR_MEMZERO(OVERLAPPED_SBUFF, overlap, 3);
+    si.cb = sizeof(si);
+
+    fflush(stdout);
+    if (timeout == 0)
+        detach = 1;
+    if (!detach) {
+        if (inp != 0 && inp->buf != 0 && inp->len != 0) {
+            if ((rc = AcrPipePair(&pipes[PIPE_STDINP_RDS],
+                                  &pipes[PIPE_STDINP_WRS],
+                                  ACR_PIPE_READ_BLOCK, 0)))
+                goto cleanup;
+            ibuf.buf = inp->buf;
+            ibuf.len = inp->len;
+        }
+        if (out != 0) {
+            if ((rc = AcrPipePair(&pipes[PIPE_STDOUT_RDS],
+                                  &pipes[PIPE_STDOUT_WRS],
+                                  ACR_PIPE_WRITE_BLOCK, 0)))
+                goto cleanup;
+            if ((rc = AcrSbInitAuto(&obuf_s, PROC_BUFFER_SIZE)))
+                goto cleanup;
+            obuf = &obuf_s;
+        }
+        if (err != 0 && err != out) {
+            if ((rc = AcrPipePair(&pipes[PIPE_STDERR_RDS],
+                                  &pipes[PIPE_STDERR_WRS],
+                                  ACR_PIPE_WRITE_BLOCK, 0)))
+                goto cleanup;
+            if ((rc = AcrSbInitAuto(&ebuf_s, PROC_BUFFER_SIZE)))
+                goto cleanup;
+            ebuf = &ebuf_s;
+        }
+    }
+    /* Fill in missing pipes */
+    if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_RDS])) {
+        pipes[PIPE_STDINP_RDS] = AcrNullPipe(GENERIC_READ, -1);
+        if (IS_INVALID_HANDLE(pipes[PIPE_STDINP_RDS])) {
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+    }
+    if (IS_INVALID_HANDLE(pipes[PIPE_STDOUT_WRS])) {
+        pipes[PIPE_STDOUT_WRS] = AcrNullPipe(GENERIC_WRITE, -1);
+        if (IS_INVALID_HANDLE(pipes[PIPE_STDOUT_WRS])) {
+            rc = ACR_GET_OS_ERROR();
+            goto cleanup;
+        }
+    }
+    if (IS_INVALID_HANDLE(pipes[PIPE_STDERR_WRS])) {
+        if (out == 0) {
+            pipes[PIPE_STDERR_WRS] = AcrNullPipe(GENERIC_WRITE, -1);
+            if (IS_INVALID_HANDLE(pipes[PIPE_STDERR_WRS])) {
+                rc = ACR_GET_OS_ERROR();
+                goto cleanup;
+            }
+        }
+        else
+            pipes[PIPE_STDERR_WRS] = pipes[PIPE_STDOUT_WRS];
+    }
+
+    /* Always use STDHANDLES
+     * They are either real handles or handles to NUL device
+     */
+    si.dwFlags |= STARTF_USESTDHANDLES;
+    dflags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+    if (!DuplicateHandle(cproc,  pipes[PIPE_STDINP_RDS],
+                         cproc, &pipes[PIPE_STDINP_RDS],
+                         0, TRUE, dflags)) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    dflags = DUPLICATE_SAME_ACCESS;
+    if (pipes[PIPE_STDERR_WRS] != pipes[PIPE_STDOUT_WRS])
+        dflags |= DUPLICATE_CLOSE_SOURCE;
+
+    if (!DuplicateHandle(cproc,  pipes[PIPE_STDOUT_WRS],
+                         cproc, &pipes[PIPE_STDOUT_WRS],
+                         0, TRUE, dflags)) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+    dflags = DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS;
+    if (!DuplicateHandle(cproc,  pipes[PIPE_STDERR_WRS],
+                         cproc, &pipes[PIPE_STDERR_WRS],
+                         0, TRUE, dflags)) {
+        rc = ACR_GET_OS_ERROR();
+        goto cleanup;
+    }
+
+    si.hStdInput  = pipes[PIPE_STDINP_RDS];
+    si.hStdOutput = pipes[PIPE_STDOUT_WRS];
+    si.hStdError  = pipes[PIPE_STDERR_WRS];
+    if (timeout > 0) {
+        endat = AcrTimeNow() + AcrTimeFromMsec(timeout);
+        polltime = PROC_TIMEOUT_STEP;
+    }
+    stdhandles[0] = GetStdHandle(STD_INPUT_HANDLE);
+    stdhandles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
+    stdhandles[2] = GetStdHandle(STD_ERROR_HANDLE);
+
+    /* Serialize access to STD handles
+     * Since we never inherit std handles directly, make sure their
+     * handle is non inherited.
+     */
+    EnterCriticalSection(&_procmgr_lock);
+    if (IS_INVALID_HANDLE(stdhandles[0]) &&
+        GetHandleInformation(stdhandles[0], &stdhinfo[0]) && (stdhinfo[0] &= HANDLE_FLAG_INHERIT))
+        SetHandleInformation(stdhandles[0], HANDLE_FLAG_INHERIT, 0);
+    if (IS_INVALID_HANDLE(stdhandles[1]) &&
+        GetHandleInformation(stdhandles[1], &stdhinfo[1]) && (stdhinfo[1] &= HANDLE_FLAG_INHERIT))
+        SetHandleInformation(stdhandles[1], HANDLE_FLAG_INHERIT, 0);
+    if (IS_INVALID_HANDLE(stdhandles[2]) &&
+        GetHandleInformation(stdhandles[2], &stdhinfo[2]) && (stdhinfo[2] &= HANDLE_FLAG_INHERIT))
+        SetHandleInformation(stdhandles[2], HANDLE_FLAG_INHERIT, 0);
+    /* Create a child
+     */
+    if (!CreateProcessW(executable,     /* Executable */
+                        argb,           /* Command line */
+                        0,
+                        0,              /* Proc & thread security attributes */
+                        TRUE,           /* Inherit handles */
+                        cflags,         /* Creation flags */
+                        envb,           /* Environment block */
+                        workdir,        /* Current directory name */
+                        &si,
+                        &pi))
+        rc = ACR_GET_OS_ERROR();
+    else
+        rs = TRUE;
+    /* Restore STD handle inheritance
+     */
+    if (stdhinfo[0])
+        SetHandleInformation(GetStdHandle(STD_INPUT_HANDLE),
+                             stdhinfo[0], stdhinfo[0]);
+    if (stdhinfo[1])
+        SetHandleInformation(GetStdHandle(STD_OUTPUT_HANDLE),
+                             stdhinfo[1], stdhinfo[1]);
+    if (stdhinfo[2])
+        SetHandleInformation(GetStdHandle(STD_ERROR_HANDLE),
+                             stdhinfo[2], stdhinfo[2]);
+    LeaveCriticalSection(&_procmgr_lock);
+    if (rc != 0)
+        goto cleanup;
+    pid = pi.dwProcessId;
+    /* Close our side of the pipes
+     */
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_RDS]);
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_WRS]);
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_WRS]);
+
+    if (detach) {
+        /* We are done in case of detached process
+         */
+        exitval = pid;
+        exitwhy = ACR_CHILD_NOTDONE;
+        ResumeThread(pi.hThread);
+        goto finished;
+    }
+    /* Setup wait handles
+     */
+    if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+        overlap[0].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[0].o.hEvent;
+    }
+    if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS]) && (out != err)) {
+        overlap[1].o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+        waithandle[waitn++] = overlap[1].o.hEvent;
+    }
+    if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS])) {
+        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.
+     * Resume the main process thread.
+     */
+    ResumeThread(pi.hThread);
+    rc = 0;
+
+    /* Sink the console pipes and wait until the child terminates.
+     */
+    do {
+        DWORD ws;
+        DWORD rd, wr;
+        BOOL  iostat;
+        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
+         * the first ReadFile/WriteFile will fail with ERROR_IO_PENDING.
+         */
+        ws = WaitForMultipleObjects(waitn, waithandle, FALSE, polltime);
+        switch (ws) {
+            case WAIT_OBJECT_0:
+                /* Signal on stdout stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDOUT_RDS])) {
+                    if (overlap[0].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDOUT_RDS],
+                                                 (LPOVERLAPPED)&overlap[0],
+                                                 &rd,
+                                                 FALSE)) {
+                            overlap[0].stat = GetLastError();
+                        }
+                        else {
+                            overlap[0].stat = 0;
+                            rd = AcrSbCatb(obuf, overlap[0].buff, rd);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(pipes[PIPE_STDOUT_RDS],
+                                      overlap[0].buff, sizeof(overlap[0].buff),
+                                      &rd, (LPOVERLAPPED)&overlap[0]);
+                    if (iostat && rd != 0) {
+                        overlap[0].stat = 0;
+                        rd = AcrSbCatb(obuf, overlap[0].buff, rd);
+                        /* Issue another read */
+                        SetEvent(overlap[0].o.hEvent);
+                    }
+                    else {
+                        overlap[0].stat = GetLastError();
+                        if (overlap[0].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+                            ResetEvent(overlap[0].o.hEvent);
+                        }
+                    }
+                }
+                if (out != 0) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_1:
+                /* Signal on stderr stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDERR_RDS])) {
+                    if (overlap[1].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDERR_RDS],
+                                                 (LPOVERLAPPED)&overlap[1],
+                                                 &rd,
+                                                 FALSE)) {
+                            overlap[1].stat = GetLastError();
+                        }
+                        else {
+                            overlap[1].stat = 0;
+                            rd = AcrSbCatb(ebuf, overlap[1].buff, rd);
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = ReadFile(pipes[PIPE_STDERR_RDS],
+                                      overlap[1].buff, sizeof(overlap[1].buff),
+                                      &rd, (LPOVERLAPPED)&overlap[1]);
+                    if (iostat && rd != 0) {
+                        overlap[1].stat = 0;
+                        rd = AcrSbCatb(ebuf, overlap[1].buff, rd);
+                        /* Issue another read */
+                        SetEvent(overlap[1].o.hEvent);
+                    }
+                    else {
+                        overlap[1].stat = GetLastError();
+                        if (overlap[1].stat != ERROR_IO_PENDING) {
+                            SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+                            ResetEvent(overlap[1].o.hEvent);
+                        }
+                    }
+                }
+                if (err != 0 && err != out) {
+                    rc = ACR_EINTR;
+                    break;
+                }
+            case WAIT_OBJECT_2:
+                /* Signal on stdin stream
+                 */
+                if (IS_VALID_HANDLE(pipes[PIPE_STDINP_WRS]) &&
+                    ibuf.len > ibuf.use) {
+                    if (overlap[2].stat == ERROR_IO_PENDING) {
+                        if (!GetOverlappedResult(pipes[PIPE_STDINP_WRS],
+                                                 (LPOVERLAPPED)&overlap[2],
+                                                 &wr,
+                                                 FALSE)) {
+                            overlap[2].stat = GetLastError();
+                        }
+                        else {
+                            overlap[2].stat = 0;
+                            ibuf.use += wr;
+                        }
+                        rc = ACR_EINTR;
+                        break;
+                    }
+                    iostat = WriteFile(pipes[PIPE_STDINP_WRS],
+                                       ibuf.buf + ibuf.use,
+                                       ibuf.len - ibuf.use, &wr,
+                                       (LPOVERLAPPED)&overlap[2]);
+                    if (iostat && wr != 0) {
+                        ibuf.use += wr;
+                    }
+                    else {
+                        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[1].o.hEvent);
+                        }
+                    }
+                }
+                rc = ACR_EINTR;
+            break;
+            case WAIT_TIMEOUT:
+                if (AcrTimeNow() >= endat)
+                    rc = ACR_TIMEUP;
+            break;
+            default:
+                /* Unexpected result from Wait
+                 */
+                rc = ACR_GET_OS_ERROR();
+            break;
+        }
+    } while (rc == ACR_EINTR);
+
+    do {
+        DWORD ws;
+        /* Wait until child ends
+         */
+        ws = WaitForSingleObject(pi.hProcess, polltime);
+        switch (ws) {
+            case WAIT_OBJECT_0:
+                /* Operation success */
+                GetExitCodeProcess(pi.hProcess, &exitval);
+                rc = 0;
+                rs = FALSE;
+            break;
+            case WAIT_TIMEOUT:
+                if (AcrTimeNow() >= 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.
+         * Time to kill the bugger
+         */
+        TerminateProcess(pi.hProcess, SIGKILL);
+        exitwhy = ACR_CHILD_SIGNAL;
+        exitval = SIGKILL;
+    }
+    else {
+        exitwhy = ACR_CHILD_DONE;
+    }
+
+finished:
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDINP_WRS]);
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDOUT_RDS]);
+    SAFE_CLOSE_HANDLE(pipes[PIPE_STDERR_RDS]);
+    SAFE_CLOSE_HANDLE(pi.hThread);
+    SAFE_CLOSE_HANDLE(pi.hProcess);
+    for (i = 0; i < 3; i++) {
+        SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
+    }
+    if (obuf != 0) {
+        out->len = AcrSbLen(obuf);
+        out->buf = AcrSbDetach(obuf);
+    }
+    if (ebuf != 0) {
+        err->len = AcrSbLen(ebuf);
+        err->buf = AcrSbDetach(ebuf);
+    }
+    if (ibuf.buf != 0)
+        inp->use = ibuf.use;
+    *retval = exitval;
+    return exitwhy;
+
+cleanup:
+    SAFE_CLOSE_HANDLE(pi.hThread);
+    SAFE_CLOSE_HANDLE(pi.hProcess);
+    AcrSbFree(obuf);
+    AcrSbFree(ebuf);
+    if (pipes[PIPE_STDERR_RDS] == pipes[PIPE_STDOUT_RDS])
+        pipes[PIPE_STDERR_RDS] = 0;
+    for (i = 0; i < PIPE_COUNT; i++)
+        SAFE_CLOSE_HANDLE(pipes[i]);
+    for (i = 0; i < 3; i++) {
+        SAFE_CLOSE_HANDLE(overlap[i].o.hEvent);
+    }
+    *retval = rc;
     return ACR_PARENT_ERROR;
 }
 
@@ -80,14 +522,15 @@ ACR_JNI_EXPORT(jobject, ExecImpl, init0)
         return 0;
     R_LOAD_METHOD(0000, 0);
     _clazzn.u = 1;
+    _procmgr_init();
     return (*env)->NewObject(env, _clazzn.i, J4MID(0000));
 }
 
-ACR_UNX_EXPORT(jlong, PosixExec, run0)(JNI_STDARGS, jstring executable,
-                                       jstring args, jstring envb,
-                                       jstring cwd, jbyteArray inp,
-                                       jobject out, jobject err,
-                                       jint timeout)
+ACR_WIN_EXPORT(jlong, WindowsExec, run0)(JNI_STDARGS, jstring executable,
+                                         jstring args, jcharArray envs,
+                                         jstring cwd, jbyteArray inp,
+                                         jobject out, jobject err,
+                                         jint timeout)
 {
     int rv = 0;
     int rc = 0;
@@ -95,8 +538,10 @@ ACR_UNX_EXPORT(jlong, PosixExec, run0)(J
     acr_buf_t *ib = 0;
     acr_buf_t *ob = 0;
     acr_buf_t *eb = 0;
-    
+    wchar_t *envb = 0;
+
     WITH_WSTR(executable) {
+    WITH_WSTR(args) {
     WITH_WSTR(cwd) {
         if (inp != 0) {
             ib = &bb[0];
@@ -107,12 +552,16 @@ ACR_UNX_EXPORT(jlong, PosixExec, run0)(J
             ob = &bb[1];
         if (err != 0 && err != out)
             eb = &bb[2];
+        if (envs != 0)
+            envb = (*env)->GetPrimitiveArrayCritical(env, envs, 0);
         /* Call actual execute
          */
-        rv = _run_exec(J2S(executable), 0, 0, J2S(cwd),
+        rv = _run_exec(J2S(executable), J2S(args), 0, J2S(cwd),
                        ob, eb, ib, timeout, &rc);
         if (ib != 0 && inp != 0)
             (*env)->ReleasePrimitiveArrayCritical(env, inp, ib->buf, 0);
+        if (envs != 0)
+            (*env)->ReleasePrimitiveArrayCritical(env, envs, envb, 0);
         if (rv != ACR_PARENT_ERROR) {
             if (out != 0) {
                 /* Write to the output stream */
@@ -136,8 +585,9 @@ cleanup:
         if (ob != 0)
             AcrFree(ob->buf);
         if (eb != 0)
-            AcrFree(ob->buf);
+            AcrFree(eb->buf);
     } DONE_WITH_STR(cwd);
+    } DONE_WITH_STR(args);
     } DONE_WITH_STR(executable);
 
     return ((jlong)rv << 32) | ((jlong)rc & ACR_I64_C(0xFFFFFFFF));

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/util.c Thu Apr 28 13:22:14 2011
@@ -16,9 +16,12 @@
 
 #include "acr/error.h"
 #include "acr/memory.h"
+#include "acr/iodefs.h"
 #include "acr/port.h"
 #include "arch_opts.h"
 
+#define PIPE_FMT    "\\\\.\\pipe\\00000000-0000-0000-0000-000000000000"
+static volatile LONG _pipe_id = 23;
 /* This is the helper code to resolve late bound entry points
  * missing from one or more releases of the Win32 API
  */
@@ -118,3 +121,201 @@ AcrLoadLateDLLs()
     }
     return 0;
 }
+
+/* Similar to posix dup3 but it only actually works for
+ * stdio handles. If newfd is not stdio handle this
+ * behaves like DuplicateHandle favoring ACR_FOPEN_NOINHERIT
+ * flag.
+ */
+HANDLE dup4(HANDLE hproc, HANDLE oldfd, int flags)
+{
+    HANDLE duph    = INVALID_HANDLE_VALUE;
+    DWORD  inherit = TRUE;
+
+    if (IS_INVALID_HANDLE(oldfd)) {
+        ACR_SET_OS_ERROR(ACR_EINVAL);
+        return INVALID_HANDLE_VALUE;
+    }
+    if (flags & ACR_FOPEN_NOINHERIT)
+        inherit = FALSE;
+    if (!DuplicateHandle(hproc,
+                         oldfd,
+                         hproc,
+                         &duph,
+                         0,
+                         inherit,
+                         DUPLICATE_SAME_ACCESS))
+        duph = INVALID_HANDLE_VALUE;
+    return duph;
+}
+
+/* Similar to posix dup3 but it only actually works for
+ * stdio handles. If newfd is not stdio handle this
+ * behaves like DuplicateHandle favoring ACR_FOPEN_NOINHERIT
+ * flag.
+ */
+HANDLE dup3(HANDLE oldfd, int newfd, int flags)
+{
+    int    osfd;
+    DWORD  saved_errno = 0;
+    HANDLE duph = INVALID_HANDLE_VALUE;
+    DWORD  inherit = TRUE;
+    int    oflags  = 0;
+    FILE  *stream  = 0;
+
+    if (IS_INVALID_HANDLE(oldfd)) {
+        ACR_SET_OS_ERROR(ACR_EINVAL);
+        return INVALID_HANDLE_VALUE;
+    }
+    if (flags & ACR_FOPEN_NOINHERIT)
+        inherit = FALSE;
+    switch (newfd) {
+        case STDIN_FILENO:
+            oflags = _O_RDONLY;
+        break;
+        case STDOUT_FILENO:
+            stream = stdout;
+            oflags = _O_WRONLY;
+        break;
+        case STDERR_FILENO:
+            stream = stderr;
+            oflags = _O_WRONLY;
+        break;
+        default:
+            return dup4(GetCurrentProcess(), oldfd, flags);
+        break;
+    }
+    if (stream != 0) {
+        fflush(stream);
+        setvbuf(stream, NULL, _IONBF, 0);
+    }
+    osfd = _open_osfhandle((INT_PTR)oldfd, oflags | _O_BINARY);
+    if (osfd == -1) {
+        return INVALID_HANDLE_VALUE;
+    }
+    if (_dup2(osfd, newfd) == -1) {
+        return INVALID_HANDLE_VALUE;
+    }
+    _setmode(newfd, _O_BINARY);
+    duph = (HANDLE)_get_osfhandle(newfd);
+    if (IS_VALID_HANDLE(duph)) {
+        if (!inherit)
+            SetHandleInformation(duph, HANDLE_FLAG_INHERIT, 0);
+        /* _dup2 will not set sdh handles for GUI apps */
+        switch (newfd) {
+            case STDIN_FILENO:
+                SetStdHandle(STD_INPUT_HANDLE,  duph);
+            break;
+            case STDOUT_FILENO:
+                SetStdHandle(STD_OUTPUT_HANDLE, duph);
+            break;
+            case STDERR_FILENO:
+                SetStdHandle(STD_ERROR_HANDLE,  duph);
+            break;
+        }
+    }
+    return duph;
+}
+
+HANDLE
+AcrNullPipe(int flags, int fd)
+{
+    SECURITY_ATTRIBUTES sa;
+    HANDLE nd;
+    HANDLE dh;
+    DWORD  saved_errno = 0;
+
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.bInheritHandle       = TRUE;
+    sa.lpSecurityDescriptor = NULL;
+
+    nd = CreateFileW(L"NUL",
+                     flags,
+                     0,
+                     &sa,
+                     OPEN_EXISTING,
+                     FILE_ATTRIBUTE_NORMAL,
+                     NULL);
+    if (IS_INVALID_HANDLE(nd))
+        return NULL;
+    if (fd == -1)
+        return nd;
+    dh = dup3(nd, fd, flags);
+    if (IS_INVALID_HANDLE(dh))
+        saved_errno = GetLastError();
+    CloseHandle(nd);
+    if (saved_errno)
+        SetLastError(saved_errno);
+    return dh;
+}
+
+int
+AcrPipeNameFromIdA(DWORD dwPid, DWORD dwId, LPSTR lpszName, DWORD dwNameLength)
+{
+    if (lpszName == 0 || dwNameLength == 0)
+        return ISIZEOF(PIPE_FMT);
+    return  _snprintf(lpszName, dwNameLength,
+                      "\\\\.\\pipe\\%08x-0000-%04x-0000-000000000000",
+                       dwPid, dwId & 0xffff);
+}
+
+int
+AcrPipePair(HANDLE *rd, HANDLE *wr, int flags, char *name)
+{
+    int rc = 0;
+    SECURITY_ATTRIBUTES sa;
+    DWORD dwOpenMode;
+    DWORD dwPipeMode;
+    char  rname[RESOURCE_NAME_LEN];
+
+    if (name == 0)
+        name = rname;
+    AcrPipeNameFromIdA(GetCurrentProcessId(),
+                       (DWORD)InterlockedIncrement(&_pipe_id),
+                       name, RESOURCE_NAME_LEN);
+
+    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
+    sa.bInheritHandle       = FALSE;
+    sa.lpSecurityDescriptor = 0;
+
+    if (rd != 0) {
+        dwOpenMode = PIPE_ACCESS_INBOUND;
+        dwPipeMode = 0;
+        if (flags == ACR_PIPE_WRITE_BLOCK ||
+            flags == ACR_PIPE_FULL_NONBLOCK)
+            dwOpenMode |= FILE_FLAG_OVERLAPPED;
+
+        *rd = CreateNamedPipeA(name,
+                               dwOpenMode,
+                               dwPipeMode,
+                               1,
+                               0,
+                               65536,
+                               1,
+                               &sa);
+        if (IS_INVALID_HANDLE(*rd))
+            return ACR_GET_OS_ERROR();
+    }
+    if (wr != 0) {
+        dwOpenMode = FILE_ATTRIBUTE_NORMAL;
+        if (flags == ACR_PIPE_READ_BLOCK ||
+            flags == ACR_PIPE_FULL_NONBLOCK)
+            dwOpenMode |= FILE_FLAG_OVERLAPPED;
+        *wr = CreateFileA(name,
+                          GENERIC_WRITE,
+                          0,
+                          &sa,
+                          OPEN_EXISTING,
+                          dwOpenMode,
+                          0);
+        if (IS_INVALID_HANDLE(*wr)) {
+            rc = ACR_GET_OS_ERROR();
+            if (rd != 0) {
+                SAFE_CLOSE_HANDLE(*rd);
+            }
+            return rc;
+        }
+    }
+    return 0;
+}
+

Modified: commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java?rev=1097447&r1=1097446&r2=1097447&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java (original)
+++ commons/sandbox/runtime/trunk/src/main/test/org/apache/commons/runtime/TestExec.java Thu Apr 28 13:22:14 2011
@@ -40,7 +40,8 @@ public class TestExec extends Assert
             args.add("-al");
         }
         else {
-
+            args.add("C:\\Windows\\System32\\cmd.exe");
+            args.add("/V");
         }
         e.redirectOutputStream(true);
         e.redirectErrorStream(true);