]> granicus.if.org Git - postgresql/blobdiff - src/backend/port/win32/signal.c
Update copyright via script for 2017
[postgresql] / src / backend / port / win32 / signal.c
index c073c84b34682db4e46ea3411583c2ccecf3336b..ebbd434b9a8bef6e22ea0bb3d4396a38f48bef53 100644 (file)
@@ -3,17 +3,17 @@
  * signal.c
  *       Microsoft Windows Win32 Signal Emulation Functions
  *
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.19 2007/10/23 17:58:01 mha Exp $
+ *       src/backend/port/win32/signal.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
-#include <libpq/pqsignal.h>
+#include "libpq/pqsignal.h"
 
 /*
  * These are exported for use by the UNBLOCKED_SIGNAL_QUEUE() macro.
@@ -33,6 +33,7 @@ HANDLE                pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
  */
 static CRITICAL_SECTION pg_signal_crit_sec;
 
+/* Note that array elements 0 are unused since they correspond to signal 0 */
 static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
 static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
 
@@ -83,18 +84,18 @@ pgwin32_signal_initialize(void)
        pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (pgwin32_signal_event == NULL)
                ereport(FATAL,
-                               (errmsg_internal("failed to create signal event: %d", (int) GetLastError())));
+                               (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
 
        /* Create thread for handling signals */
        signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
        if (signal_thread_handle == NULL)
                ereport(FATAL,
-                               (errmsg_internal("failed to create signal handler thread")));
+                               (errmsg_internal("could not create signal handler thread")));
 
        /* Create console control handle to pick up Ctrl-C etc */
        if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
                ereport(FATAL,
-                               (errmsg_internal("failed to set console control handler")));
+                               (errmsg_internal("could not set console control handler")));
 }
 
 /*
@@ -105,15 +106,15 @@ pgwin32_signal_initialize(void)
 void
 pgwin32_dispatch_queued_signals(void)
 {
-       int                     i;
+       int                     exec_mask;
 
        EnterCriticalSection(&pg_signal_crit_sec);
-       while (UNBLOCKED_SIGNAL_QUEUE())
+       while ((exec_mask = UNBLOCKED_SIGNAL_QUEUE()) != 0)
        {
                /* One or more unblocked signals queued for execution */
-               int                     exec_mask = UNBLOCKED_SIGNAL_QUEUE();
+               int                     i;
 
-               for (i = 0; i < PG_SIGNAL_COUNT; i++)
+               for (i = 1; i < PG_SIGNAL_COUNT; i++)
                {
                        if (exec_mask & sigmask(i))
                        {
@@ -158,7 +159,11 @@ pqsigsetmask(int mask)
 }
 
 
-/* signal manipulation. Only called on main thread, no sync required */
+/*
+ * Unix-like signal handler installation
+ *
+ * Only called on main thread, no sync required
+ */
 pqsigfunc
 pqsignal(int signum, pqsigfunc handler)
 {
@@ -171,7 +176,7 @@ pqsignal(int signum, pqsigfunc handler)
        return prevfunc;
 }
 
-/* Create the signal listener pipe for specified pid */
+/* Create the signal listener pipe for specified PID */
 HANDLE
 pgwin32_create_signal_listener(pid_t pid)
 {
@@ -186,8 +191,8 @@ pgwin32_create_signal_listener(pid_t pid)
 
        if (pipe == INVALID_HANDLE_VALUE)
                ereport(ERROR,
-                               (errmsg("could not create signal listener pipe for pid %d: error code %d",
-                                               (int) pid, (int) GetLastError())));
+                               (errmsg("could not create signal listener pipe for PID %d: error code %lu",
+                                               (int) pid, GetLastError())));
 
        return pipe;
 }
@@ -251,7 +256,7 @@ pg_signal_thread(LPVOID param)
        char            pipename[128];
        HANDLE          pipe = pgwin32_initial_signal_pipe;
 
-       snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", GetCurrentProcessId());
+       snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
 
        for (;;)
        {
@@ -266,7 +271,7 @@ pg_signal_thread(LPVOID param)
 
                        if (pipe == INVALID_HANDLE_VALUE)
                        {
-                               write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError());
+                               write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
                                SleepEx(500, FALSE);
                                continue;
                        }
@@ -275,21 +280,63 @@ pg_signal_thread(LPVOID param)
                fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
                if (fConnected)
                {
+                       HANDLE          newpipe;
+
+                       /*
+                        * We have a connected pipe. Pass this off to a separate thread
+                        * that will do the actual processing of the pipe.
+                        *
+                        * We must also create a new instance of the pipe *before* we
+                        * start running the new thread. If we don't, there is a race
+                        * condition whereby the dispatch thread might run CloseHandle()
+                        * before we have created a new instance, thereby causing a small
+                        * window of time where we will miss incoming requests.
+                        */
+                       newpipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
+                                          PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                                                          PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
+                       if (newpipe == INVALID_HANDLE_VALUE)
+                       {
+                               /*
+                                * This really should never fail. Just retry in case it does,
+                                * even though we have a small race window in that case. There
+                                * is nothing else we can do other than abort the whole
+                                * process which will be even worse.
+                                */
+                               write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
+
+                               /*
+                                * Keep going so we at least dispatch this signal. Hopefully,
+                                * the call will succeed when retried in the loop soon after.
+                                */
+                       }
                        hThread = CreateThread(NULL, 0,
                                                  (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
                                                                   (LPVOID) pipe, 0, NULL);
                        if (hThread == INVALID_HANDLE_VALUE)
-                               write_stderr("could not create signal dispatch thread: error code %d\n",
-                                                        (int) GetLastError());
+                               write_stderr("could not create signal dispatch thread: error code %lu\n",
+                                                        GetLastError());
                        else
                                CloseHandle(hThread);
+
+                       /*
+                        * Background thread is running with our instance of the pipe. So
+                        * replace our reference with the newly created one and loop back
+                        * up for another run.
+                        */
+                       pipe = newpipe;
                }
                else
-                       /* Connection failed. Cleanup and try again */
+               {
+                       /*
+                        * Connection failed. Cleanup and try again.
+                        *
+                        * This should never happen. If it does, we have a small race
+                        * condition until we loop up and re-create the pipe.
+                        */
                        CloseHandle(pipe);
-
-               /* Set up so we create a new pipe on next loop */
-               pipe = INVALID_HANDLE_VALUE;
+                       pipe = INVALID_HANDLE_VALUE;
+               }
        }
        return 0;
 }