#include "postgres.h"
#include "libpq/pqsignal.h"
Go to the source code of this file.
Functions | |
static DWORD WINAPI | pg_signal_thread (LPVOID param) |
static BOOL WINAPI | pg_console_handler (DWORD dwCtrlType) |
void | pg_usleep (long microsec) |
void | pgwin32_signal_initialize (void) |
void | pgwin32_dispatch_queued_signals (void) |
int | pqsigsetmask (int mask) |
pqsigfunc | pqsignal (int signum, pqsigfunc handler) |
HANDLE | pgwin32_create_signal_listener (pid_t pid) |
void | pg_queue_signal (int signum) |
static DWORD WINAPI | pg_signal_dispatch_thread (LPVOID param) |
Variables | |
volatile int | pg_signal_queue |
int | pg_signal_mask |
HANDLE | pgwin32_signal_event |
HANDLE | pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE |
static CRITICAL_SECTION | pg_signal_crit_sec |
static pqsigfunc | pg_signal_array [PG_SIGNAL_COUNT] |
static pqsigfunc | pg_signal_defaults [PG_SIGNAL_COUNT] |
static BOOL WINAPI pg_console_handler | ( | DWORD | dwCtrlType | ) | [static] |
Definition at line 347 of file signal.c.
References pg_queue_signal().
Referenced by pgwin32_signal_initialize().
{ 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; }
void pg_queue_signal | ( | int | signum | ) |
Definition at line 209 of file signal.c.
References pg_signal_crit_sec, pg_signal_queue, pgwin32_signal_event, and sigmask.
Referenced by pg_console_handler(), pg_signal_dispatch_thread(), and pg_timer_thread().
{ if (signum >= PG_SIGNAL_COUNT || signum <= 0) return; EnterCriticalSection(&pg_signal_crit_sec); pg_signal_queue |= sigmask(signum); LeaveCriticalSection(&pg_signal_crit_sec); SetEvent(pgwin32_signal_event); }
static DWORD WINAPI pg_signal_dispatch_thread | ( | LPVOID | param | ) | [static] |
Definition at line 223 of file signal.c.
References NULL, and pg_queue_signal().
Referenced by pg_signal_thread().
{ 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; }
static DWORD WINAPI pg_signal_thread | ( | LPVOID | param | ) | [static] |
Definition at line 253 of file signal.c.
References BOOL(), FALSE, NULL, pg_signal_dispatch_thread(), pgwin32_initial_signal_pipe, snprintf(), TRUE, and write_stderr.
Referenced by pgwin32_signal_initialize().
{ char pipename[128]; HANDLE pipe = pgwin32_initial_signal_pipe; snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId()); for (;;) { BOOL fConnected; HANDLE hThread; if (pipe == INVALID_HANDLE_VALUE) { 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 %lu; retrying\n", GetLastError()); SleepEx(500, FALSE); continue; } } 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 %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. * * This should never happen. If it does, we have a small race * condition until we loop up and re-create the pipe. */ CloseHandle(pipe); pipe = INVALID_HANDLE_VALUE; } } return 0; }
void pg_usleep | ( | long | microsec | ) |
Definition at line 52 of file signal.c.
Referenced by auth_delay_checks(), AutoVacLauncherMain(), AutoVacWorkerMain(), backend_read_statsfile(), BackendInitialize(), BackgroundWriterMain(), CheckpointerMain(), CheckpointWriteDelay(), CountOtherDBBackends(), CreateCheckPoint(), CustomizableNextWALFileReady(), do_pg_stop_backup(), do_restart(), do_start_bgworker(), do_stop(), do_watch(), FileRead(), FileWrite(), ForgetDatabaseFsyncRequests(), ForgetRelationFsyncRequests(), GetMultiXactIdMembers(), InitPostgres(), lazy_truncate_heap(), main(), pg_sleep(), pgarch_ArchiverCopyLoop(), pgwin32_recv(), recoveryPausesHere(), register_unlink(), regression_main(), RequestCheckpoint(), ResolveRecoveryConflictWithDatabase(), ResolveRecoveryConflictWithVirtualXIDs(), RestoreWALFileForRecovery(), s_lock(), ServerLoop(), ShutdownWalRcv(), StartupXLOG(), StreamConnection(), test_postmaster_connection(), vacuum_delay_point(), WaitExceedsMaxStandbyDelay(), WaitForWALToBecomeAvailable(), WalWriterMain(), and XLogFlush().
{ if (WaitForSingleObject(pgwin32_signal_event, (microsec < 500 ? 1 : (microsec + 500) / 1000)) == WAIT_OBJECT_0) { pgwin32_dispatch_queued_signals(); errno = EINTR; return; } }
HANDLE pgwin32_create_signal_listener | ( | pid_t | pid | ) |
Definition at line 180 of file signal.c.
References ereport, errmsg(), ERROR, NULL, and snprintf().
{ 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 %lu", (int) pid, GetLastError()))); return pipe; }
void pgwin32_dispatch_queued_signals | ( | void | ) |
Definition at line 106 of file signal.c.
References i, pg_signal_array, pg_signal_crit_sec, pg_signal_defaults, pg_signal_queue, pgwin32_signal_event, sig, SIG_DFL, SIG_ERR, SIG_IGN, sigmask, and UNBLOCKED_SIGNAL_QUEUE.
Referenced by pg_usleep(), PGSemaphoreLock(), pgwin32_poll_signals(), pgwin32_select(), pgwin32_waitforsinglesocket(), pqsigsetmask(), and WaitLatchOrSocket().
{ int i; EnterCriticalSection(&pg_signal_crit_sec); while (UNBLOCKED_SIGNAL_QUEUE()) { /* One or more unblocked signals queued for execution */ int exec_mask = UNBLOCKED_SIGNAL_QUEUE(); 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 */ } } } } ResetEvent(pgwin32_signal_event); LeaveCriticalSection(&pg_signal_crit_sec); }
void pgwin32_signal_initialize | ( | void | ) |
Definition at line 67 of file signal.c.
References ereport, errmsg_internal(), FALSE, FATAL, i, NULL, pg_console_handler(), pg_signal_array, pg_signal_crit_sec, pg_signal_defaults, pg_signal_mask, pg_signal_queue, pg_signal_thread(), pgwin32_signal_event, and TRUE.
Referenced by main().
{ 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; /* Create the global event handle used to flag signals */ pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (pgwin32_signal_event == NULL) ereport(FATAL, (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("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("could not set console control handler"))); }
Definition at line 167 of file signal.c.
Referenced by AutoVacLauncherMain(), AutoVacWorkerMain(), BackendInitialize(), BackgroundWriterMain(), bootstrap_signals(), CheckpointerMain(), ClosePager(), do_copy(), do_start_bgworker(), InitializeTimeouts(), main(), PageOutput(), PgArchiverMain(), PgstatCollectorMain(), plperl_init_interp(), PostgresMain(), PostmasterMain(), PQprint(), setalarm(), setQFout(), setup_cancel_handler(), setup_signals(), sigquit_handler(), StartupProcessMain(), SysLoggerMain(), trapsig(), WalReceiverMain(), WalSndSignals(), and WalWriterMain().
{ pqsigfunc prevfunc; if (signum >= PG_SIGNAL_COUNT || signum < 0) return SIG_ERR; prevfunc = pg_signal_array[signum]; pg_signal_array[signum] = handler; return prevfunc; }
int pqsigsetmask | ( | int | mask | ) |
Definition at line 144 of file signal.c.
References pg_signal_mask, and pgwin32_dispatch_queued_signals().
{ 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 */ pgwin32_dispatch_queued_signals(); return prevmask; }
pqsigfunc pg_signal_array[PG_SIGNAL_COUNT] [static] |
Definition at line 36 of file signal.c.
Referenced by pgwin32_dispatch_queued_signals(), pgwin32_signal_initialize(), and pqsignal().
CRITICAL_SECTION pg_signal_crit_sec [static] |
Definition at line 34 of file signal.c.
Referenced by pg_queue_signal(), pgwin32_dispatch_queued_signals(), and pgwin32_signal_initialize().
pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT] [static] |
Definition at line 37 of file signal.c.
Referenced by pgwin32_dispatch_queued_signals(), and pgwin32_signal_initialize().
int pg_signal_mask |
Definition at line 25 of file signal.c.
Referenced by pgwin32_signal_initialize(), and pqsigsetmask().
volatile int pg_signal_queue |
Definition at line 24 of file signal.c.
Referenced by pg_queue_signal(), pgwin32_dispatch_queued_signals(), and pgwin32_signal_initialize().
HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE |
Definition at line 28 of file signal.c.
Referenced by pg_signal_thread().
HANDLE pgwin32_signal_event |
Definition at line 27 of file signal.c.
Referenced by pg_queue_signal(), pg_usleep(), PGSemaphoreLock(), pgwin32_dispatch_queued_signals(), pgwin32_select(), pgwin32_signal_initialize(), pgwin32_waitforsinglesocket(), and WaitLatchOrSocket().