Author: mturk Date: Mon Sep 14 13:18:30 2009 New Revision: 814630 URL: http://svn.apache.org/viewvc?rev=814630&view=rev Log: More on win32 signals. Lot's of debugging in there that will go away
Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_signals.h commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_private.h commons/sandbox/runtime/trunk/src/main/native/os/unix/signals.c commons/sandbox/runtime/trunk/src/main/native/os/win32/main.c commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c commons/sandbox/runtime/trunk/src/main/native/os/win32/wusec.c commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestSemaphore.java Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_signals.h URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_signals.h?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/include/acr_signals.h (original) +++ commons/sandbox/runtime/trunk/src/main/native/include/acr_signals.h Mon Sep 14 13:18:30 2009 @@ -44,9 +44,16 @@ */ ACR_DECLARE(const char *) ACR_SignalDescription(int signum); +/** + * Send a signal to the process. + * @param sal Signal security key. + * @param sig signal to send. + * @param to pid of the process + */ +ACR_DECLARE(int) ACR_SendSignal(const acr_pchar_t *salt, int signum, int to); + #ifdef __cplusplus } #endif #endif /* _ACR_SIGNALS_H */ - 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=814630&r1=814629&r2=814630&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 Mon Sep 14 13:18:30 2009 @@ -134,6 +134,8 @@ LPVOID ACR_StdSecurityDescriptor(JNIEnv *, int, int); DWORD ACR_SetSecurityInfo(HANDLE, int, PSID, PSID, int); +PSECURITY_ATTRIBUTES ACR_GetSaWithNullDacl(void); + /** * Events from main.c */ Modified: commons/sandbox/runtime/trunk/src/main/native/os/unix/signals.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/unix/signals.c?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/unix/signals.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/unix/signals.c Mon Sep 14 13:18:30 2009 @@ -53,3 +53,7 @@ return "Unknown signal (number)"; } +ACR_DECLARE(int) ACR_SendSignal(const char *salt, int signum, int to) +{ + return ACR_ENOTIMPL; +} Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/main.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/main.c?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/win32/main.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/win32/main.c Mon Sep 14 13:18:30 2009 @@ -306,17 +306,13 @@ L"Failed loading system libraries", rc); return (int)rc; } - - if ((rc = acr_SignalsInit())) { - /* Failed initializing signaling sub system - */ - return (int)rc; - } /* Up to here we can be called multiple times. */ - if (initialized++) - return 0; - + if (initialized++) { + /* Second invocation for signal init + */ + return acr_SignalsInit(); + } while (sePrivileges[i]) { if ((rc = ACR_EnablePrivilege(sePrivileges[i])) != ERROR_SUCCESS) { wchar_t buf[128]; @@ -363,11 +359,17 @@ */ em = SetErrorMode(0); SetErrorMode(em | SEM_NOOPENFILEERRORBOX); + if ((rc = acr_SignalsInit())) { + /* Failed initializing signaling sub system + */ + return (int)rc; + } #if defined(DEBUG) fprintf(stdout, "\nInitialized ACR : %S\n", dll_file_name); fprintf(stdout, " : %S\n", dos_file_name); fflush(stdout); #endif + return 0; } Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c Mon Sep 14 13:18:30 2009 @@ -55,6 +55,16 @@ volatile LONG current_signal_listeners; static SIG_PF signal_handlers[ACR_NUMSIG]; +static volatile int signal_handlers_running; + + +/* We use 4 instances as default + * The real number should be numCPU * 2 + */ +static int sig_pipe_instances = 4; +static HANDLE sig_pipe_handle = INVALID_HANDLE_VALUE; +static wchar_t sig_pipe_name[64]; +static wchar_t sig_pipe_salt[64]; static void make_security_cookie(acr_sig_msg_t *msg, const wchar_t *salt, DWORD sn, DWORD to) @@ -64,7 +74,7 @@ acr_uint32_t tc = GetTickCount(); ACR_SHA1Init(&sha); - if (salt) + if (salt && *salt) ACR_SHA1UpdateW(&sha, salt, wcslen(salt)); ACR_SHA1Update(&sha, (unsigned char *)&sn, sizeof(acr_uint32_t)); ACR_SHA1Update(&sha, (unsigned char *)&me, sizeof(acr_uint32_t)); @@ -84,7 +94,7 @@ acr_uint32_t me = GetCurrentProcessId(); ACR_SHA1Init(&sha); - if (salt) + if (salt && *salt) ACR_SHA1UpdateW(&sha, salt, wcslen(salt)); ACR_SHA1Update(&sha, (unsigned char *)&(msg->signal), sizeof(acr_uint32_t)); @@ -97,6 +107,27 @@ return memcmp(digest, msg->cookie, 20); } +/* Write an empty message to the pipe. + * So we can bail out from the ConnectNamedPipe call + */ +static void ping_sig_pipe(int state) +{ + DWORD read = 0; + acr_sig_msg_t msg; + + signal_handlers_running = state; + if (IS_INVALID_HANDLE(sig_pipe_handle)) + return; + memset(&msg, 0, sizeof(acr_sig_msg_t)); + CallNamedPipeW(sig_pipe_name, + &msg, + (DWORD)sizeof(acr_sig_msg_t), + &msg, + (DWORD)sizeof(acr_sig_msg_t), + &read, + NMPWAIT_NOWAIT); +} + /* Default signal handler. */ static void default_signal_handler(int sig) @@ -104,6 +135,7 @@ JNIEnv *_E; switch (sig) { case SIGKILL: + ping_sig_pipe(0); /* Call the System.exit(9) */ if (ACR_SystemExit(NULL, sig)) { @@ -117,6 +149,7 @@ break; case SIGBUS: case SIGSEGV: + ping_sig_pipe(0); _E = ACR_GetJNIEnv(); if (IS_VALID_HANDLE(_E)) { (*_E)->FatalError(_E, strsignal(sig)); @@ -132,6 +165,7 @@ /* Do nothing */ #if defined(DEBUG) fprintf(stderr, "[native] Unhandled - %s\n", strsignal(sig)); + fflush(stderr); #endif break; } @@ -197,15 +231,127 @@ * the signal. */ SetEvent(dll_auto_hevent); - SetEvent(dll_psig_handle); LeaveCriticalSection(&signal_lock); - handled = TRUE; + if (signal_handlers[posix_signal] == SIG_DFL) { +#if defined(DEBUG) + fprintf(stdout, "[native] Default console handler for - %s\n", + strsignal(posix_signal)); + fflush(stdout); +#endif + /* Execute default signal hadler + */ + } + else + handled = TRUE; } return handled; } -static volatile int signal_handlers_running; +static DWORD WINAPI read_signal_thread(LPVOID param) +{ + DWORD read = 0; + HANDLE pipe = (HANDLE)param; + acr_sig_msg_t msg; +#if defined(DEBUG) + fprintf(stdout, "Started read thread\n"); + fflush(stdout); +#endif + for (;;) { + memset(&msg, 0, sizeof(acr_sig_msg_t)); + if (!ReadFile(pipe, + &msg, + (DWORD)sizeof(acr_sig_msg_t), + &read, + NULL)) { + /* Read failed. */ + break; + } + if (read != sizeof(acr_sig_msg_t)) { + /* Invalid message size. + */ +#if defined(DEBUG) + fprintf(stderr, "Received invalid message size %d\n", read); + fflush(stderr); +#endif + break; + } + if (verify_security_cookie(&msg, sig_pipe_salt)) { + /* Invalid message signature. + */ +#if defined(DEBUG) + fprintf(stderr, "Received invalid message signature\n"); + fflush(stderr); +#endif + break; + } +#if defined(DEBUG) + fprintf(stdout, "Received valid signal %d from %d\n", + msg.signal, msg.sender); + fflush(stdout); +#endif + msg.sender = GetCurrentProcessId(); + /* Write the message back with our pid as sender. + * We don't care about the result of the write operation. + */ + WriteFile(pipe, &msg, (DWORD)sizeof(acr_sig_msg_t), &read, NULL); + FlushFileBuffers(pipe); + DisconnectNamedPipe(pipe); + CloseHandle(pipe); + + /* Deliver a signal */ + /* Sync with callback handler */ + EnterCriticalSection(&signal_lock); +#if defined(_MSC_VER) && (_MSC_VER >= 1300) + /* XXX: Do we really need an atomic op here? + */ + _InterlockedOr(¤t_signal_queue, sigmask(msg.signal)); +#else + /* We don't have compiler intrinsic. + * CriticalSection should guard the value for the majority + * of cases. + */ + current_signal_queue |= sigmask(msg.signal); +#endif + /* Fire the signal events. + * The first locked listener will handle + * the signal. + */ + SetEvent(dll_auto_hevent); + LeaveCriticalSection(&signal_lock); + } + CloseHandle(pipe); + return 0; +} + +static DWORD WINAPI main_signal_monitor(LPVOID unused) +{ + DWORD rc; + while (signal_handlers_running) { + rc = WaitForSingleObject(dll_auto_hevent, INFINITE); + if (rc == WAIT_OBJECT_0) { + /* Dispatch the event to object waiters + */ + EnterCriticalSection(&signal_lock); + if (ACR_SIGNAL_NWAITERS() == 0) { + LeaveCriticalSection(&signal_lock); + rc = ACR_DeliverSignals(); + } + else { + LeaveCriticalSection(&signal_lock); + SetEvent(dll_psig_handle); + } + } + else { + /* Anything else is a fault. + * Terminate the monitor thread + */ + signal_handlers_running = 0; + break; + } + } + return 0; +} /* Main signal thread is responsible for handling the signal * events. * Once created it will remain running until application exit, @@ -220,13 +366,71 @@ fflush(stdout); #endif while (signal_handlers_running) { + BOOL connected; + if (IS_INVALID_HANDLE(sig_pipe_handle)) { + sig_pipe_handle = CreateNamedPipeW(sig_pipe_name, + PIPE_ACCESS_DUPLEX, /* ###: We only read */ + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + sig_pipe_instances, + (DWORD)sizeof(acr_sig_msg_t), + (DWORD)sizeof(acr_sig_msg_t), + 2000, + ACR_GetSaWithNullDacl()); + if (IS_INVALID_HANDLE(sig_pipe_handle)) { + /* Failed to create signal messaging pipe + * for this process. Retry after 500ms. + */ +#if defined(DEBUG) + fprintf(stderr, "Could not create listener pipe '%S' - %d\n", + sig_pipe_name, GetLastError()); + fflush(stderr); +#endif + SleepEx(500, FALSE); + continue; + } + } +#if defined(DEBUG) + fprintf(stdout, "Waiting for a client on '%S'\n", + sig_pipe_name); + fflush(stdout); +#endif + if (!(connected = ConnectNamedPipe(sig_pipe_handle, NULL))) { + if (GetLastError() == ERROR_PIPE_CONNECTED) + connected = TRUE; + } +#if defined(DEBUG) + fprintf(stdout, "Client on '%S' is %s\n", + sig_pipe_name, connected ? "connected" : "not connected"); + fflush(stdout); +#endif + if (connected && signal_handlers_running) { + /* We have connected client. + * Start the cleint worker thread + */ + HANDLE wt; + DWORD wi; + if (!(wt = CreateThread(NULL, + 0, + read_signal_thread, + (LPVOID)sig_pipe_handle, + 0, + &wi))) { - /* Until we implement the pupmp. - */ - Sleep(1000); + } + else + CloseHandle(wt); + + } + else { + /* Connect failed. + * Close the pipe and try again. + */ + CloseHandle(sig_pipe_handle); + } + sig_pipe_handle = INVALID_HANDLE_VALUE; } #if defined(DEBUG) - fprintf(stdout, "\n[native] Terminated signalig subsystem for %d\n", + fprintf(stdout, "\n[native] Terminated signaling subsystem for %d\n", GetCurrentProcessId()); fflush(stdout); #endif @@ -235,7 +439,8 @@ int acr_SignalsInit() { - DWORD i; + HANDLE h; + DWORD i; /* Guard against multiple invocations. * We might initialize twice; in daemon and in JVM again @@ -267,13 +472,49 @@ signal_handlers[SIGSEGV] = default_signal_handler; signal_handlers[SIGKILL] = default_signal_handler; signal_handlers[SIGTERM] = default_signal_handler; + signal_handlers[SIGINT] = SIG_DFL; - if (!CreateThread(NULL, - 0, - main_signal_thread, - NULL, - 0, - &i)) { + /* Get the global signal pipe name. + * Combined from pid and ACR_NUMSIG. + */ + pipe_name_from_pid(sig_pipe_name, GetCurrentProcessId(), ACR_NUMSIG); + sig_pipe_handle = CreateNamedPipeW(sig_pipe_name, + PIPE_ACCESS_DUPLEX, /* ###: We only read */ + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + sig_pipe_instances, + (DWORD)sizeof(acr_sig_msg_t), + (DWORD)sizeof(acr_sig_msg_t), + 2000, + ACR_GetSaWithNullDacl()); + if (IS_INVALID_HANDLE(sig_pipe_handle)) { + /* Failed to create signal messaging pipe + * for this process. Bail out. + * + * ###: We could just continue from here as well. + * Signal thread wold retry to create this pipe + * on regular intervals. + */ + return ACR_GET_OS_ERROR(); + } + if (!(h = CreateThread(NULL, + 0, + main_signal_monitor, + NULL, + 0, + &i))) { + /* Failed creating thread. + * If we ever get here the system is + * unstable and will probably crash + * in the near future. Anyhow, return the error. + */ + return ACR_GET_OS_ERROR(); + } + if (!(h = CreateThread(NULL, + 0, + main_signal_thread, + NULL, + 0, + &i))) { /* Failed creating thread. * If we ever get here the system is * unstable and will probably crash @@ -314,10 +555,11 @@ /* Someone just entered while we obtained the lock */ } - if ((mask = (current_signal_queue & ~current_signal_mask))) { + while ((mask = (current_signal_queue & ~current_signal_mask))) { int i; - for (i = 1; i < ACR_NUMSIG, rc == ACR_EINTR; i++) { + for (i = 1; i < ACR_NUMSIG; i++) { if (mask & sigmask(i)) { + SIG_PF sig = signal_handlers[i]; switch (i) { case SIGKILL: case SIGQUIT: @@ -328,11 +570,25 @@ rc = ACR_EINTR; break; } - if (signal_handlers[i-1] != SIG_IGN) { + /* Remove the signal from the queue + */ +#if defined(_MSC_VER) && (_MSC_VER >= 1300) + /* XXX: Do we really need an atomic op here? + */ + _InterlockedAnd(¤t_signal_queue, ~sigmask(msg.signal)); +#else + current_signal_queue &= ~sigmask(i); +#endif + if (sig != SIG_IGN && sig != SIG_ERR) { + LeaveCriticalSection(&signal_lock); /* TODO: Handle default signals */ - (*signal_handlers[i-1])(i); + sig(i); + EnterCriticalSection(&signal_lock); + break; } } + if (rc != ACR_EINTR) + break; } } LeaveCriticalSection(&signal_lock); @@ -348,3 +604,26 @@ else return "Unknown signal (number)"; } + +ACR_DECLARE(int) ACR_SendSignal(const wchar_t *salt, int signum, int to) +{ + DWORD read; + acr_sig_msg_t msg; + acr_sig_msg_t buf; + wchar_t name[64]; + + pipe_name_from_pid(name, to, ACR_NUMSIG); + make_security_cookie(&msg, salt, signum, to); + if (CallNamedPipeW(name, + &msg, + (DWORD)sizeof(acr_sig_msg_t), + &buf, + (DWORD)sizeof(acr_sig_msg_t), + &read, + NMPWAIT_USE_DEFAULT_WAIT)) { + return 0; + } + else { + ACR_GET_OS_ERROR(); + } +} Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/wusec.c URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/wusec.c?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/os/win32/wusec.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/os/win32/wusec.c Mon Sep 14 13:18:30 2009 @@ -534,3 +534,57 @@ } return SetSecurityInfo(handle, ko, sinf, uid, gid, dacl, NULL); } + + +static PSECURITY_ATTRIBUTES _null_sa = NULL; +static SECURITY_ATTRIBUTES _empty_sa; +/* To share the objects with other processes, we need a NULL ACL + * Code from MS KB Q106387 + */ +PSECURITY_ATTRIBUTES ACR_GetSaWithNullDacl() +{ + DWORD rc = 0; + PSECURITY_DESCRIPTOR pSD; + + + if (_null_sa) + return _null_sa; + + _null_sa = (PSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); + _null_sa->nLength = sizeof(SECURITY_ATTRIBUTES); + + pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); + _null_sa->lpSecurityDescriptor = pSD; + if (pSD == NULL || _null_sa == NULL) { + rc = ACR_ENOMEM; + goto cleanup; + } + if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { + rc = GetLastError(); + goto cleanup; + } + if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL)NULL, FALSE)) { + rc = ACR_ENOMEM; + goto cleanup; + } + _null_sa->lpSecurityDescriptor = pSD; + _null_sa->bInheritHandle = FALSE; + + SetLastError(0); + return _null_sa; + +cleanup: + if (pSD) + LocalFree(pSD); + if (_null_sa) { + LocalFree(_null_sa); + _null_sa = NULL; + } + _null_sa = &_empty_sa; + _null_sa->nLength = sizeof(SECURITY_ATTRIBUTES); + _null_sa->lpSecurityDescriptor = NULL; + _null_sa->bInheritHandle = FALSE; + + SetLastError(rc); + return _null_sa; +} 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=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c (original) +++ commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c Mon Sep 14 13:18:30 2009 @@ -38,21 +38,25 @@ #include "acr_ring.h" #include "acr_ini.h" #include "acr_port.h" +#include "acr_signals.h" #include "acr_time.h" #include "acr_version.h" #if defined (WIN32) #include <io.h> +#include <process.h> #include <sys/stat.h> #define random rand #define srandom srand #define PRINT_PSTR "%S" #define STD_PREFIX L"acr-test-" +#define _TXT(X) L ## X #else extern mode_t acr_default_umask; extern mode_t acr_default_perms; #define PRINT_PSTR "%s" #define STD_PREFIX "acr-test-" +#define _TXT(X) X #endif @@ -194,7 +198,16 @@ jvmso = argv[0]; jvmcp = argv[1]; +#if defined(WIN32) + { + wchar_t pb[8192]; + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + jvmso, -1, pb, sizeof(pb)); + dso = ACR_DsoLoad(NULL, pb); + } +#else dso = ACR_DsoLoad(NULL, jvmso); +#endif if (dso < 0) { fprintf(stderr, "Cannot load JVM from %s\n", jvmso); fflush(stderr); @@ -429,7 +442,6 @@ { int i; size_t mp = 0; - char buf[1024]; const char *end = NULL; if (argc < 2) { @@ -440,9 +452,13 @@ printf("smatch returned %d\n", i); printf("smatch ended on '%s'\n", argv[0] + mp); #if !defined(WIN32) - printf("original string is %s.\n", argv[0]); - shquote(argv[0], buf, 1024); - printf("quoted string is %s.\n", buf); + { + char buf[1024]; + + printf("original string is %s.\n", argv[0]); + shquote(argv[0], buf, 1024); + printf("quoted string is %s.\n", buf); + } #endif return 0; } @@ -508,6 +524,28 @@ return 0; } +static int test_signal(int argc, const char *const argv[]) +{ + int failed = 0; + int ppid; + if (argc < 1) { + return ACR_EINVAL; + } + if (*argv[0] == 's') { + printf("Server waiting %d\n", getpid()); +#if defined(WIN32) + Sleep(10000); +#endif + } + else { + ppid = atoi(argv[0]); + if (ppid == 0) + return ACR_EINVAL; + ACR_SendSignal(NULL, SIGBUS, ppid); + } + return 0; +} + int main(int argc, const char *const argv[]) { int rv = 0; @@ -590,8 +628,9 @@ else if (!strcasecmp(run_test, "pmatch")) { rv = test_pmatch(argc, argv); } - - x_free(run_test); + else if (!strcasecmp(run_test, "signal")) { + rv = test_signal(argc, argv); + } } cleanup: Modified: commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestSemaphore.java URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestSemaphore.java?rev=814630&r1=814629&r2=814630&view=diff ============================================================================== --- commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestSemaphore.java (original) +++ commons/sandbox/runtime/trunk/src/test/org/apache/commons/runtime/TestSemaphore.java Mon Sep 14 13:18:30 2009 @@ -80,5 +80,19 @@ } test003(s); } + + public void testTestSemaphoreSleep() + throws Throwable + { + boolean owner = TestParams.getInstance().isChild(); + if (owner) { + try { + System.out.println("Sleeping for 1 second"); + Thread.sleep(1000); + } catch (Throwable t) { + // Ignore + } + } + } }