1
/*-------------------------------------------------------------------------
4
* Microsoft Windows Win32 Signal Emulation Functions
6
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
9
* $PostgreSQL: pgsql/src/backend/port/win32/signal.c,v 1.11 2004-12-31 22:00:37 pgsql Exp $
11
*-------------------------------------------------------------------------
16
#include <libpq/pqsignal.h>
19
/* pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
20
* variable that can be accessed from the signal sending threads! */
21
static CRITICAL_SECTION pg_signal_crit_sec;
22
static int pg_signal_queue;
24
static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
25
static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
26
static int pg_signal_mask;
28
DLLIMPORT HANDLE pgwin32_signal_event;
29
HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
32
/* Signal handling thread function */
33
static DWORD WINAPI pg_signal_thread(LPVOID param);
34
static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
36
/* Sleep function that can be interrupted by signals */
38
pgwin32_backend_usleep(long microsec)
40
if (WaitForSingleObject(pgwin32_signal_event, (microsec < 500 ? 1 : (microsec + 500) / 1000)) == WAIT_OBJECT_0)
42
pgwin32_dispatch_queued_signals();
51
pgwin32_signal_initialize(void)
54
HANDLE signal_thread_handle;
56
InitializeCriticalSection(&pg_signal_crit_sec);
58
for (i = 0; i < PG_SIGNAL_COUNT; i++)
60
pg_signal_array[i] = SIG_DFL;
61
pg_signal_defaults[i] = SIG_IGN;
66
/* Create the global event handle used to flag signals */
67
pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
68
if (pgwin32_signal_event == NULL)
70
(errmsg_internal("failed to create signal event: %d", (int) GetLastError())));
72
/* Create thread for handling signals */
73
signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
74
if (signal_thread_handle == NULL)
76
(errmsg_internal("failed to create signal handler thread")));
78
/* Create console control handle to pick up Ctrl-C etc */
79
if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
81
(errmsg_internal("failed to set console control handler")));
85
/* Dispatch all signals currently queued and not blocked
86
* Blocked signals are ignored, and will be fired at the time of
87
* the sigsetmask() call. */
89
pgwin32_dispatch_queued_signals(void)
93
EnterCriticalSection(&pg_signal_crit_sec);
94
while (pg_signal_queue & ~pg_signal_mask)
96
/* One or more unblocked signals queued for execution */
98
int exec_mask = pg_signal_queue & ~pg_signal_mask;
100
for (i = 0; i < PG_SIGNAL_COUNT; i++)
102
if (exec_mask & sigmask(i))
104
/* Execute this signal */
105
pqsigfunc sig = pg_signal_array[i];
108
sig = pg_signal_defaults[i];
109
pg_signal_queue &= ~sigmask(i);
110
if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
112
LeaveCriticalSection(&pg_signal_crit_sec);
114
EnterCriticalSection(&pg_signal_crit_sec);
115
break; /* Restart outer loop, in case signal mask
116
* or queue has been modified inside
122
ResetEvent(pgwin32_signal_event);
123
LeaveCriticalSection(&pg_signal_crit_sec);
126
/* signal masking. Only called on main thread, no sync required */
128
pqsigsetmask(int mask)
132
prevmask = pg_signal_mask;
133
pg_signal_mask = mask;
136
* Dispatch any signals queued up right away, in case we have
137
* unblocked one or more signals previously queued
139
pgwin32_dispatch_queued_signals();
145
/* signal manipulation. Only called on main thread, no sync required */
147
pqsignal(int signum, pqsigfunc handler)
151
if (signum >= PG_SIGNAL_COUNT || signum < 0)
153
prevfunc = pg_signal_array[signum];
154
pg_signal_array[signum] = handler;
158
/* Create the signal listener pipe for specified pid */
160
pgwin32_create_signal_listener(pid_t pid)
165
wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", (int) pid);
167
pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
168
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
169
PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
171
if (pipe == INVALID_HANDLE_VALUE)
173
(errmsg("could not create signal listener pipe for pid %d: error code %d",
174
(int) pid, (int) GetLastError())));
181
* All functions below execute on the signal handler thread
182
* and must be synchronized as such!
183
* NOTE! The only global variable that can be used is
189
pg_queue_signal(int signum)
191
if (signum >= PG_SIGNAL_COUNT || signum <= 0)
194
EnterCriticalSection(&pg_signal_crit_sec);
195
pg_signal_queue |= sigmask(signum);
196
LeaveCriticalSection(&pg_signal_crit_sec);
198
SetEvent(pgwin32_signal_event);
201
/* Signal dispatching thread */
203
pg_signal_dispatch_thread(LPVOID param)
205
HANDLE pipe = (HANDLE) param;
209
if (!ReadFile(pipe, &sigNum, 1, &bytes, NULL))
211
/* Client died before sending */
217
/* Received <bytes> bytes over signal pipe (should be 1) */
221
WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it works
223
FlushFileBuffers(pipe);
224
DisconnectNamedPipe(pipe);
227
pg_queue_signal(sigNum);
231
/* Signal handling thread */
233
pg_signal_thread(LPVOID param)
236
HANDLE pipe = pgwin32_initial_signal_pipe;
238
wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%d", GetCurrentProcessId());
245
if (pipe == INVALID_HANDLE_VALUE)
247
pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
248
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
249
PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
251
if (pipe == INVALID_HANDLE_VALUE)
253
write_stderr("could not create signal listener pipe: error code %d; retrying\n", (int) GetLastError());
259
fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
262
hThread = CreateThread(NULL, 0,
263
(LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
264
(LPVOID) pipe, 0, NULL);
265
if (hThread == INVALID_HANDLE_VALUE)
266
write_stderr("could not create signal dispatch thread: error code %d\n",
267
(int) GetLastError());
269
CloseHandle(hThread);
272
/* Connection failed. Cleanup and try again */
275
/* Set up so we create a new pipe on next loop */
276
pipe = INVALID_HANDLE_VALUE;
282
/* Console control handler will execute on a thread created
283
by the OS at the time of invocation */
285
pg_console_handler(DWORD dwCtrlType)
287
if (dwCtrlType == CTRL_C_EVENT ||
288
dwCtrlType == CTRL_BREAK_EVENT ||
289
dwCtrlType == CTRL_CLOSE_EVENT ||
290
dwCtrlType == CTRL_SHUTDOWN_EVENT)
292
pg_queue_signal(SIGINT);