diff options
Diffstat (limited to 'src/backend/libpq/pqsignal.c')
-rw-r--r-- | src/backend/libpq/pqsignal.c | 295 |
1 files changed, 4 insertions, 291 deletions
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index 34e5883797e..dc1f6ccc087 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.32 2004/02/18 16:25:12 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.33 2004/04/12 16:19:18 momjian Exp $ * * NOTES * This shouldn't be in libpq, but the monitor and some other @@ -38,9 +38,6 @@ * is to do signal-handler reinstallation, which doesn't work well * at all. * ------------------------------------------------------------------------*/ -#ifdef WIN32 -#define _WIN32_WINNT 0x0400 -#endif #include "postgres.h" @@ -131,7 +128,9 @@ pqinitmask(void) } +/* Win32 signal handling is in backend/port/win32/signal.c */ #ifndef WIN32 + /* * Set up a signal handler */ @@ -154,290 +153,4 @@ pqsignal(int signo, pqsigfunc func) return oact.sa_handler; #endif /* !HAVE_POSIX_SIGNALS */ } - - -#else - - -/* Win32 specific signals code */ - -/* 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; - -HANDLE pgwin32_main_thread_handle; - -/* Signal handling thread function */ -static DWORD WINAPI pg_signal_thread(LPVOID param); -static BOOL WINAPI pg_console_handler(DWORD dwCtrlType); - -/* Initialization */ -void -pgwin32_signal_initialize(void) -{ - int i; - HANDLE signal_thread_handle; - - InitializeCriticalSection(&pg_signal_crit_sec); - - for (i = 0; i < PG_SIGNAL_COUNT; i++) - { - pg_signal_array[i] = SIG_DFL; - pg_signal_defaults[i] = SIG_IGN; - } - pg_signal_mask = 0; - pg_signal_queue = 0; - - /* Get handle to main thread so we can post calls to it later */ - if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &pgwin32_main_thread_handle, - 0, FALSE, DUPLICATE_SAME_ACCESS)) - ereport(FATAL, - (errmsg_internal("Failed to get main thread handle!"))); - - /* 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!"))); - - if (!SetConsoleCtrlHandler(pg_console_handler, TRUE)) - ereport(FATAL, - (errmsg_internal("Failed to set console control handler!"))); -} - - -/* Dispatch all signals currently queued and not blocked - * Blocked signals are ignored, and will be fired at the time of - * the sigsetmask() call. */ -static void -dispatch_queued_signals(void) -{ - int i; - - EnterCriticalSection(&pg_signal_crit_sec); - while (pg_signal_queue & ~pg_signal_mask) - { - /* One or more unblocked signals queued for execution */ - - int exec_mask = pg_signal_queue & ~pg_signal_mask; - - for (i = 0; i < PG_SIGNAL_COUNT; i++) - { - if (exec_mask & sigmask(i)) - { - /* Execute this signal */ - pqsigfunc sig = pg_signal_array[i]; - - if (sig == SIG_DFL) - sig = pg_signal_defaults[i]; - pg_signal_queue &= ~sigmask(i); - if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL) - { - 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 */ - } - } - } - } - LeaveCriticalSection(&pg_signal_crit_sec); -} - -/* signal masking. Only called on main thread, no sync required */ -int -pqsigsetmask(int mask) -{ - int prevmask; - - prevmask = pg_signal_mask; - pg_signal_mask = mask; - - /* - * Dispatch any signals queued up right away, in case we have - * unblocked one or more signals previously queued - */ - dispatch_queued_signals(); - - return prevmask; -} - - -/* signal manipulation. Only called on main thread, no sync required */ -pqsigfunc -pqsignal(int signum, pqsigfunc handler) -{ - pqsigfunc prevfunc; - - if (signum >= PG_SIGNAL_COUNT || signum < 0) - return SIG_ERR; - prevfunc = pg_signal_array[signum]; - pg_signal_array[signum] = handler; - return prevfunc; -} - -/* signal sending */ -int -pqkill(int pid, int sig) -{ - char pipename[128]; - BYTE sigData = sig; - BYTE sigRet = 0; - DWORD bytes; - - if (sig >= PG_SIGNAL_COUNT || sig <= 0) - { - errno = EINVAL; - return -1; - } - if (pid <= 0) - { - /* No support for process groups */ - errno = EINVAL; - return -1; - } - wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", pid); - if (!CallNamedPipe(pipename, &sigData, 1, &sigRet, 1, &bytes, 1000)) - { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errno = ESRCH; - else if (GetLastError() == ERROR_ACCESS_DENIED) - errno = EPERM; - else - errno = EINVAL; - return -1; - } - if (bytes != 1 || sigRet != sig) - { - errno = ESRCH; - return -1; - } - - return 0; -} - -/* APC callback scheduled on main thread when signals are fired */ -static void CALLBACK -pg_signal_apc(ULONG_PTR param) -{ - dispatch_queued_signals(); -} - -/* - * All functions below execute on the signal handler thread - * and must be synchronized as such! - * NOTE! The only global variable that can be used is - * pg_signal_queue! - */ - - -void -pg_queue_signal(int signum) -{ - if (signum >= PG_SIGNAL_COUNT || signum < 0) - return; - - EnterCriticalSection(&pg_signal_crit_sec); - pg_signal_queue |= sigmask(signum); - LeaveCriticalSection(&pg_signal_crit_sec); - - QueueUserAPC(pg_signal_apc, pgwin32_main_thread_handle, (ULONG_PTR) NULL); -} - -/* Signal dispatching thread */ -static DWORD WINAPI -pg_signal_dispatch_thread(LPVOID param) -{ - HANDLE pipe = (HANDLE) param; - BYTE sigNum; - DWORD bytes; - - if (!ReadFile(pipe, &sigNum, 1, &bytes, NULL)) - { - /* Client died before sending */ - CloseHandle(pipe); - return 0; - } - if (bytes != 1) - { - /* Received <bytes> bytes over signal pipe (should be 1) */ - CloseHandle(pipe); - return 0; - } - WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it works - * or not.. */ - FlushFileBuffers(pipe); - DisconnectNamedPipe(pipe); - CloseHandle(pipe); - - pg_queue_signal(sigNum); - return 0; -} - -/* Signal handling thread */ -static DWORD WINAPI -pg_signal_thread(LPVOID param) -{ - char pipename[128]; - HANDLE pipe = INVALID_HANDLE_VALUE; - - wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", 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, TRUE); - continue; - } - - fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); - if (fConnected) - { - hThread = CreateThread(NULL, 0, - (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()); - else - CloseHandle(hThread); - } - else - /* Connection failed. Cleanup and try again */ - CloseHandle(pipe); - } - return 0; -} - - -/* 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) { - if (dwCtrlType == CTRL_C_EVENT || - dwCtrlType == CTRL_BREAK_EVENT || - dwCtrlType == CTRL_CLOSE_EVENT || - dwCtrlType == CTRL_SHUTDOWN_EVENT) { - pg_queue_signal(SIGINT); - return TRUE; - } - return FALSE; -} - - -#endif +#endif /* WIN32 */ |