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));