X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=src%2Fbackend%2Fport%2Fwin32%2Fsignal.c;h=b291370f54993a1e93ceed669ac89dbb64d35686;hb=74be86847c8cdd274a274fc9384988cb81756d87;hp=25786cfdc051d6fb98c1c4f521834fadea4d23c4;hpb=6f21f4adaa87f7ba4dedda01a1c392ee472f43c2;p=postgresql diff --git a/src/backend/port/win32/signal.c b/src/backend/port/win32/signal.c index 25786cfdc0..b291370f54 100644 --- a/src/backend/port/win32/signal.c +++ b/src/backend/port/win32/signal.c @@ -3,10 +3,10 @@ * signal.c * Microsoft Windows Win32 Signal Emulation Functions * - * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.2 2004/05/27 13:08:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.21 2008/04/16 22:16:00 adunstan Exp $ * *------------------------------------------------------------------------- */ @@ -15,27 +15,46 @@ #include +/* + * These are exported for use by the UNBLOCKED_SIGNAL_QUEUE() macro. + * pg_signal_queue must be volatile since it is changed by the signal + * handling thread and inspected without any lock by the main thread. + * pg_signal_mask is only changed by main thread so shouldn't need it. + */ +volatile int pg_signal_queue; +int pg_signal_mask; + +HANDLE pgwin32_signal_event; +HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE; -/* pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only - * variable that can be accessed from the signal sending threads! */ +/* + * pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only + * variable that can be accessed from the signal sending threads! + */ static CRITICAL_SECTION pg_signal_crit_sec; -static int pg_signal_queue; -#define PG_SIGNAL_COUNT 32 static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT]; static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT]; -static int pg_signal_mask; - -DLLIMPORT HANDLE pgwin32_signal_event; /* Signal handling thread function */ static DWORD WINAPI pg_signal_thread(LPVOID param); static BOOL WINAPI pg_console_handler(DWORD dwCtrlType); -/* Sleep function that can be interrupted by signals */ -void pgwin32_backend_usleep(long microsec) { - if (WaitForSingleObject(pgwin32_signal_event, (microsec < 500 ? 1 : (microsec + 500) / 1000)) == WAIT_OBJECT_0) { + +/* + * pg_usleep --- delay the specified number of microseconds, but + * stop waiting if a signal arrives. + * + * This replaces the non-signal-aware version provided by src/port/pgsleep.c. + */ +void +pg_usleep(long microsec) +{ + if (WaitForSingleObject(pgwin32_signal_event, + (microsec < 500 ? 1 : (microsec + 500) / 1000)) + == WAIT_OBJECT_0) + { pgwin32_dispatch_queued_signals(); errno = EINTR; return; @@ -62,37 +81,37 @@ pgwin32_signal_initialize(void) /* Create the global event handle used to flag signals */ pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (pgwin32_signal_event == NULL) + if (pgwin32_signal_event == NULL) ereport(FATAL, - (errmsg_internal("Failed to create signal event: %i!",(int)GetLastError()))); + (errmsg_internal("failed to create signal event: %d", (int) 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("failed to create signal handler thread"))); /* Create console control handle to pick up Ctrl-C etc */ - if (!SetConsoleCtrlHandler(pg_console_handler, TRUE)) + if (!SetConsoleCtrlHandler(pg_console_handler, TRUE)) ereport(FATAL, - (errmsg_internal("Failed to set console control handler!"))); + (errmsg_internal("failed to set console control handler"))); } - -/* Dispatch all signals currently queued and not blocked +/* + * Dispatch all signals currently queued and not blocked * Blocked signals are ignored, and will be fired at the time of - * the sigsetmask() call. */ + * the sigsetmask() call. + */ void pgwin32_dispatch_queued_signals(void) { int i; EnterCriticalSection(&pg_signal_crit_sec); - while (pg_signal_queue & ~pg_signal_mask) + while (UNBLOCKED_SIGNAL_QUEUE()) { /* One or more unblocked signals queued for execution */ - - int exec_mask = pg_signal_queue & ~pg_signal_mask; + int exec_mask = UNBLOCKED_SIGNAL_QUEUE(); for (i = 0; i < PG_SIGNAL_COUNT; i++) { @@ -109,9 +128,9 @@ pgwin32_dispatch_queued_signals(void) LeaveCriticalSection(&pg_signal_crit_sec); sig(i); EnterCriticalSection(&pg_signal_crit_sec); - break; /* Restart outer loop, in case signal mask - * or queue has been modified inside - * signal handler */ + break; /* Restart outer loop, in case signal mask or + * queue has been modified inside signal + * handler */ } } } @@ -130,8 +149,8 @@ pqsigsetmask(int mask) pg_signal_mask = mask; /* - * Dispatch any signals queued up right away, in case we have - * unblocked one or more signals previously queued + * Dispatch any signals queued up right away, in case we have unblocked + * one or more signals previously queued */ pgwin32_dispatch_queued_signals(); @@ -152,6 +171,28 @@ pqsignal(int signum, pqsigfunc handler) return prevfunc; } +/* Create the signal listener pipe for specified pid */ +HANDLE +pgwin32_create_signal_listener(pid_t pid) +{ + char pipename[128]; + HANDLE pipe; + + snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid); + + pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL); + + if (pipe == INVALID_HANDLE_VALUE) + ereport(ERROR, + (errmsg("could not create signal listener pipe for pid %d: error code %d", + (int) pid, (int) GetLastError()))); + + return pipe; +} + + /* * All functions below execute on the signal handler thread * and must be synchronized as such! @@ -163,7 +204,7 @@ pqsignal(int signum, pqsigfunc handler) void pg_queue_signal(int signum) { - if (signum >= PG_SIGNAL_COUNT || signum < 0) + if (signum >= PG_SIGNAL_COUNT || signum <= 0) return; EnterCriticalSection(&pg_signal_crit_sec); @@ -193,8 +234,8 @@ pg_signal_dispatch_thread(LPVOID param) CloseHandle(pipe); return 0; } - WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it works - * or not.. */ + WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it works or + * not.. */ FlushFileBuffers(pipe); DisconnectNamedPipe(pipe); CloseHandle(pipe); @@ -208,51 +249,62 @@ static DWORD WINAPI pg_signal_thread(LPVOID param) { char pipename[128]; - HANDLE pipe = INVALID_HANDLE_VALUE; + HANDLE pipe = pgwin32_initial_signal_pipe; - wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", GetCurrentProcessId()); + snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId()); for (;;) { BOOL fConnected; HANDLE hThread; - pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL); if (pipe == INVALID_HANDLE_VALUE) { - fprintf(stderr, gettext("Failed to create signal listener pipe: %i. Retrying.\n"), (int) GetLastError()); - SleepEx(500, FALSE); - continue; + pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL); + + if (pipe == INVALID_HANDLE_VALUE) + { + write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError()); + SleepEx(500, FALSE); + continue; + } } fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (fConnected) { hThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread, + (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread, (LPVOID) pipe, 0, NULL); if (hThread == INVALID_HANDLE_VALUE) - fprintf(stderr, gettext("Failed to create signal dispatch thread: %i\n"), (int) GetLastError()); + write_stderr("could not create signal dispatch thread: error code %d\n", + (int) GetLastError()); else CloseHandle(hThread); } else /* Connection failed. Cleanup and try again */ CloseHandle(pipe); + + /* Set up so we create a new pipe on next loop */ + pipe = INVALID_HANDLE_VALUE; } return 0; } -/* Console control handler will execute on a thread created +/* Console control handler will execute on a thread created by the OS at the time of invocation */ -static BOOL WINAPI pg_console_handler(DWORD dwCtrlType) { +static BOOL WINAPI +pg_console_handler(DWORD dwCtrlType) +{ if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT || dwCtrlType == CTRL_CLOSE_EVENT || - dwCtrlType == CTRL_SHUTDOWN_EVENT) { + dwCtrlType == CTRL_SHUTDOWN_EVENT) + { pg_queue_signal(SIGINT); return TRUE; }