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 2009/09/14 20:35:32 UTC

svn commit: r814773 - in /commons/sandbox/runtime/trunk/src/main/native: os/win32/signals.c test/testsuite.c

Author: mturk
Date: Mon Sep 14 18:35:32 2009
New Revision: 814773

URL: http://svn.apache.org/viewvc?rev=814773&view=rev
Log:
Implement signals using completion ports

Modified:
    commons/sandbox/runtime/trunk/src/main/native/os/win32/signals.c
    commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c

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=814773&r1=814772&r2=814773&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 18:35:32 2009
@@ -47,6 +47,7 @@
 #else
 #define ACR_NUMSIG  33
 #endif
+#define PIPE_TIMEOUT    1000
 
 static CRITICAL_SECTION signal_lock;
 int           dll_daemon_mode = 0;
@@ -58,14 +59,16 @@
 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];
 
+typedef struct sig_pipe_data_t {
+    OVERLAPPED    ctx;
+    acr_sig_msg_t msg;
+    HANDLE        pipe;
+} sig_pipe_data_t;
+
 static void make_security_cookie(acr_sig_msg_t *msg, const wchar_t *salt,
                                  DWORD sn, DWORD to)
 {
@@ -107,30 +110,6 @@
     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)) {
-        /* Pipe is already closed.
-         * Nothing to do.
-         */
-        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.
  */
@@ -139,7 +118,6 @@
     JNIEnv *_E;
     switch (sig) {
         case SIGKILL:
-            ping_sig_pipe(0);
             /* Call the System.exit(9)
              */
             if (ACR_SystemExit(NULL, sig)) {
@@ -153,7 +131,6 @@
         break;
         case SIGBUS:
         case SIGSEGV:
-            ping_sig_pipe(0);
             _E = ACR_GetJNIEnv();
             if (IS_VALID_HANDLE(_E)) {
                 (*_E)->FatalError(_E, strsignal(sig));
@@ -241,203 +218,209 @@
     return handled;
 }
 
-static DWORD WINAPI read_signal_thread(LPVOID param)
-{
-    DWORD  read = 0;
-    HANDLE pipe = (HANDLE)param;
-    acr_sig_msg_t msg;
 
-    memset(&msg, 0, sizeof(acr_sig_msg_t));
-    if (!ReadFile(pipe,
-                  &msg,
-                  (DWORD)sizeof(acr_sig_msg_t),
-                  &read,
-                  NULL)) {
-        /* Read failed. */
-        goto cleanup;
-    }
-    if (!signal_handlers_running) {
-        /* We just received a message
-         * probably from ping_sig_pipe and the
-         * signal subsytem is marked for shutdown.
-         * Close the pipe and bail out.
-         */
-        goto cleanup;
-    }
-    if (read != sizeof(acr_sig_msg_t)) {
-        /* Invalid message size.
-         */
+static void WINAPI completion_write(DWORD, DWORD, LPOVERLAPPED);
+static void WINAPI completion_sread(DWORD err, DWORD nread,
+                                    LPOVERLAPPED lpo)
+{
+    sig_pipe_data_t *pd = (sig_pipe_data_t *)lpo;
+    BOOL ws = FALSE;
+
+    if ((err == 0) && (nread == (DWORD)sizeof(acr_sig_msg_t))) {
+        if (verify_security_cookie(&pd->msg, sig_pipe_salt)) {
+            /* Invalid message signature.
+             */
 #if defined(DEBUG)
-        fprintf(stderr, "Received invalid message size %d\n", read);
-        fflush(stderr);
+            fprintf(stderr, "Received invalid message signature\n");
+            fflush(stderr);
 #endif
-        goto cleanup;
-    }
-    if (verify_security_cookie(&msg, sig_pipe_salt)) {
-        /* Invalid message signature.
+            goto cleanup;
+        }
+        /* Sync with signal handler */
+        EnterCriticalSection(&signal_lock);
+        current_signal_queue |= sigmask(pd->msg.signal);
+        /* Notify the signal monitor thread.
+         * Signal monitor thread will interrupt all waiters
+         * and dispatch the signals if there are no waiters pending.
          */
+        SetEvent(dll_auto_hevent);
+        LeaveCriticalSection(&signal_lock);
+
+        pd->msg.sender = GetCurrentProcessId();
+        ws = WriteFileEx(pd->pipe,
+                         &pd->msg,
+                         (DWORD)sizeof(acr_sig_msg_t),
+                         (LPOVERLAPPED)pd,
+                         (LPOVERLAPPED_COMPLETION_ROUTINE)completion_write);
 #if defined(DEBUG)
-        fprintf(stderr, "Received invalid message signature\n");
-        fflush(stderr);
+        if (!ws) {
+            fprintf(stderr, "WriteFileEx failed (%d)\n", GetLastError());
+            fflush(stderr);
+        }
 #endif
-        goto cleanup;
     }
-    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);
-    /* Sync with signal handler */
-    EnterCriticalSection(&signal_lock);
-    current_signal_queue |= sigmask(msg.signal);
-    /* Notify the signal monitor thread.
-     * Signal monitor thread will interrupt all waiters
-     * and dispatch the signals if there are no waiters pending.
-     */
-    SetEvent(dll_auto_hevent);
-    LeaveCriticalSection(&signal_lock);
 
-    return 0;
 cleanup:
-    if (IS_VALID_HANDLE(pipe)) {
-        DisconnectNamedPipe(pipe);
-        CloseHandle(pipe);
+    if (!ws) {
+        DisconnectNamedPipe(pd->pipe);
+        CloseHandle(pd->pipe);
+        x_free(pd);
     }
-    return 0;
 }
 
-static DWORD WINAPI main_signal_monitor(LPVOID unused)
+static void WINAPI completion_write(DWORD err, DWORD nsend,
+                                    LPOVERLAPPED lpo)
 {
-    DWORD rc;
+    sig_pipe_data_t *pd = (sig_pipe_data_t *)lpo;
+    BOOL rs = FALSE;
 
-    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();
-                if (rc == ACR_INCOMPLETE) {
-                    /* Signal delivery requires the
-                     * shutdown
-                     */
-                    signal_handlers_running = 0;
-                    break;
-                }
-            }
-            else {
-                LeaveCriticalSection(&signal_lock);
-                /* Since we have waiters signal the
-                 * main interrupt event.
-                 * Each of the waiters must call
-                 * ACR_DeliverSignals().
-                 * The last one will reset the event
-                 * and the first one will handle the
-                 * signal queue.
-                 */
-                SetEvent(dll_psig_handle);
-            }
-        }
-        else {
-            /* Anything else means we have to exit.
-             * Terminate the monitor thread.
-             */
-             signal_handlers_running = 0;
-             break;
+    if ((err == 0) && (nsend == 0)) {
+        rs = ReadFileEx(pd->pipe,
+                        &pd->msg,
+                        (DWORD)sizeof(acr_sig_msg_t),
+                        (LPOVERLAPPED)pd,
+                        (LPOVERLAPPED_COMPLETION_ROUTINE)completion_sread);
+#if defined(DEBUG)
+        if (!rs) {
+            fprintf(stderr, "ReadFileEx failed (%d)\n", GetLastError());
+            fflush(stderr);
         }
+#endif
+    }
+    if (!rs) {
+        DisconnectNamedPipe(pd->pipe);
+        CloseHandle(pd->pipe);
+        x_free(pd);
     }
-    return 0;
 }
 
-/* Main signal thread is responsible for handling the
- * listening of external signal messages.
- * Once created it will remain running until application exit,
- * so there is no need for any thread cleanup since we cannot
- * leak a single thread.
- */
-static DWORD WINAPI main_signal_thread(LPVOID unused)
+
+static DWORD sig_pipe_connect(LPOVERLAPPED lpo)
 {
-#if defined(DEBUG)
-    fprintf(stdout, "\n[native] Initialized signalig subsystem for %d\n",
-            GetCurrentProcessId());
-    fflush(stdout);
-#endif
+    DWORD rv = 0;
+
+    sig_pipe_handle = CreateNamedPipeW(sig_pipe_name,
+                                       PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                                       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                                       PIPE_UNLIMITED_INSTANCES,
+                                       (DWORD)sizeof(acr_sig_msg_t),
+                                       (DWORD)sizeof(acr_sig_msg_t),
+                                       PIPE_TIMEOUT,
+                                       ACR_GetSaWithNullDacl());
+    if (IS_INVALID_HANDLE(sig_pipe_handle)) {
+        return GetLastError();
+    }
+    if (ConnectNamedPipe(sig_pipe_handle, lpo)) {
+        DWORD ec = GetLastError();
+        /* Overlapped ConnectNamedPipe should return FALSE.
+         */
+        CloseHandle(sig_pipe_handle);
+        return ec;
+    }
+
+    switch (GetLastError()) {
+        case ERROR_IO_PENDING:
+            rv = ERROR_IO_PENDING;
+        break;
+        case ERROR_PIPE_CONNECTED:
+            if (SetEvent(lpo->hEvent))
+                break;
+        default:
+            rv = GetLastError();
+        break;
+    }
+    return rv;
+}
+
+static DWORD WINAPI sig_handler_main(LPVOID unused)
+{
+    OVERLAPPED sync;
+    HANDLE wh[2];
+    DWORD  nw = 1;
+    DWORD  rc;
+    DWORD  cs;
+    sig_pipe_data_t *pd;
+
+    wh[0] = dll_auto_hevent;
+    wh[1] = CreateEvent(NULL, TRUE, TRUE, NULL);
+    if (IS_VALID_HANDLE(wh[1])) {
+        sync.hEvent = wh[1];
+        nw++;
+        cs = sig_pipe_connect(&sync);
+    }
+
     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),
-                                               1000,
-                                               ACR_GetSaWithNullDacl());
-            if (IS_INVALID_HANDLE(sig_pipe_handle)) {
-                /* Failed to create signal messaging pipe
-                 * for this process. Retry after 500ms.
+        rc = WaitForMultipleObjectsEx(nw, wh, FALSE, INFINITE, TRUE);
+        switch (rc) {
+            case WAIT_OBJECT_0 + 0:
+                /* Dispatch the event to object waiters
                  */
+                EnterCriticalSection(&signal_lock);
+                if (ACR_SIGNAL_NWAITERS() == 0) {
+                    LeaveCriticalSection(&signal_lock);
+                    rc = ACR_DeliverSignals();
+                    if (rc == ACR_INCOMPLETE) {
+                        /* Signal delivery requires the
+                         * shutdown
+                         */
+                        signal_handlers_running = 0;
+                    }
+                }
+                else {
+                    LeaveCriticalSection(&signal_lock);
+                    /* Since we have waiters signal the
+                     * main interrupt event.
+                     * Each of the waiters must call
+                     * ACR_DeliverSignals().
+                     * The last one will reset the event
+                     * and the first one will handle the
+                     * signal queue.
+                     */
+                    SetEvent(dll_psig_handle);
+                }
+
+            break;
+            case WAIT_OBJECT_0 + 1:
+                if (cs == ERROR_IO_PENDING) {
+                    DWORD nr = 0;
+                    if (!GetOverlappedResult(sig_pipe_handle,
+                                             &sync,
+                                             &nr,
+                                             FALSE)) {
 #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);
+                        fprintf(stderr, "Error connecting pipe - %d\n",
+                                        GetLastError());
+                        fflush(stderr);
 #endif
-        if (connected && signal_handlers_running) {
-            /* We have connected client.
-             * Start the client worker thread
-             */
-            HANDLE wt;
-            DWORD  wi;
-            if (!(wt = CreateThread(NULL,
-                                    0,
-                                    read_signal_thread,
-                                    sig_pipe_handle,
-                                    0,
-                                    &wi))) {
-
-            }
-            else
-                CloseHandle(wt);
-
-        }
-        else {
-            /* Connect failed.
-             * Close the pipe and try again.
-             */
-            if (connected)
-                DisconnectNamedPipe(sig_pipe_handle);
-            CloseHandle(sig_pipe_handle);
+                        break;
+                    }
+                    cs = ERROR_SUCCESS;
+                }
+                if (cs == ERROR_SUCCESS) {
+                    pd = x_calloc(sizeof(sig_pipe_data_t));
+                    if (pd == NULL) {
+                        /* ###: Fatal error ?
+                         */
+                        break;
+                    }
+                    pd->pipe = sig_pipe_handle;
+                    completion_write(0, 0, (LPOVERLAPPED)pd);
+                }
+                cs = sig_pipe_connect(&sync);
+            break;
+            case WAIT_IO_COMPLETION:
+                /* Wait loop interrupt.
+                 * This is restartable operation.
+                 */
+            break;
+            case WAIT_FAILED:
+                /* One of the events was closed
+                 */
+                signal_handlers_running = 0;
+            break;
         }
-        sig_pipe_handle = INVALID_HANDLE_VALUE;
     }
-#if defined(DEBUG)
-    fprintf(stdout, "\n[native] Terminated signaling subsystem for %d\n",
-            GetCurrentProcessId());
-    fflush(stdout);
-#endif
+
     return 0;
 }
 
@@ -477,7 +460,11 @@
     signal_handlers[SIGKILL] = default_signal_handler;
     /* Default handlers for console events.
      */
+#if defined(DEBUG)
+    signal_handlers[SIGINT]  = default_signal_handler;
+#else
     signal_handlers[SIGINT]  = SIG_DFL;
+#endif
     signal_handlers[SIGTERM] = SIG_DFL;
     signal_handlers[SIGHUP]  = SIG_DFL;
 
@@ -485,40 +472,9 @@
      * 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,
-                                       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-                                       sig_pipe_instances,
-                                       (DWORD)sizeof(acr_sig_msg_t),
-                                       (DWORD)sizeof(acr_sig_msg_t),
-                                       1000,
-                                       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,
+                           sig_handler_main,
                            NULL,
                            0,
                            &i))) {
@@ -562,6 +518,7 @@
         /* Someone just entered while we obtained the lock
          */
     }
+
     while ((mask = (current_signal_queue & ~current_signal_mask))) {
         int i;
         for (i = 1; i < ACR_NUMSIG; i++) {

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=814773&r1=814772&r2=814773&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 18:35:32 2009
@@ -542,11 +542,13 @@
         ppid = atoi(argv[0]);
         if (ppid == 0)
             return ACR_EINVAL;
+        rc = ACR_RaiseSignal(NULL, SIGINT, ppid);
+        rc = ACR_RaiseSignal(NULL, SIGINT, ppid);
         rc = ACR_RaiseSignal(NULL, SIGBUS, ppid);
         if (rc) {
             char buf[256];
             fprintf(stderr, ACR_GetErrorString(rc, buf, sizeof(buf)));
-            fputc('\n', stderr);     
+            fputc('\n', stderr);
         }
     }
     return 0;