1 /*-------------------------------------------------------------------------
2 *
3 * signal.c
4 * Microsoft Windows Win32 Signal Emulation Functions
5 *
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/backend/port/win32/signal.c
10 *
11 *-------------------------------------------------------------------------
12 */
13
14 #include "postgres.h"
15
16 #include "libpq/pqsignal.h"
17
18 /*
19 * These are exported for use by the UNBLOCKED_SIGNAL_QUEUE() macro.
20 * pg_signal_queue must be volatile since it is changed by the signal
21 * handling thread and inspected without any lock by the main thread.
22 * pg_signal_mask is only changed by main thread so shouldn't need it.
23 */
24 volatile int pg_signal_queue;
25 int pg_signal_mask;
26
27 HANDLE pgwin32_signal_event;
28 HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
29
30 /*
31 * pg_signal_crit_sec is used to protect only pg_signal_queue. That is the only
32 * variable that can be accessed from the signal sending threads!
33 */
34 static CRITICAL_SECTION pg_signal_crit_sec;
35
36 /* Note that array elements 0 are unused since they correspond to signal 0 */
37 static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
38 static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
39
40
41 /* Signal handling thread functions */
42 static DWORD WINAPI pg_signal_thread(LPVOID param);
43 static BOOL WINAPI pg_console_handler(DWORD dwCtrlType);
44
45
46 /*
47 * pg_usleep --- delay the specified number of microseconds, but
48 * stop waiting if a signal arrives.
49 *
50 * This replaces the non-signal-aware version provided by src/port/pgsleep.c.
51 */
52 void
pg_usleep(long microsec)53 pg_usleep(long microsec)
54 {
55 if (WaitForSingleObject(pgwin32_signal_event,
56 (microsec < 500 ? 1 : (microsec + 500) / 1000))
57 == WAIT_OBJECT_0)
58 {
59 pgwin32_dispatch_queued_signals();
60 errno = EINTR;
61 return;
62 }
63 }
64
65
66 /* Initialization */
67 void
pgwin32_signal_initialize(void)68 pgwin32_signal_initialize(void)
69 {
70 int i;
71 HANDLE signal_thread_handle;
72
73 InitializeCriticalSection(&pg_signal_crit_sec);
74
75 for (i = 0; i < PG_SIGNAL_COUNT; i++)
76 {
77 pg_signal_array[i] = SIG_DFL;
78 pg_signal_defaults[i] = SIG_IGN;
79 }
80 pg_signal_mask = 0;
81 pg_signal_queue = 0;
82
83 /* Create the global event handle used to flag signals */
84 pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
85 if (pgwin32_signal_event == NULL)
86 ereport(FATAL,
87 (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
88
89 /* Create thread for handling signals */
90 signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
91 if (signal_thread_handle == NULL)
92 ereport(FATAL,
93 (errmsg_internal("could not create signal handler thread")));
94
95 /* Create console control handle to pick up Ctrl-C etc */
96 if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
97 ereport(FATAL,
98 (errmsg_internal("could not set console control handler")));
99 }
100
101 /*
102 * Dispatch all signals currently queued and not blocked
103 * Blocked signals are ignored, and will be fired at the time of
104 * the sigsetmask() call.
105 */
106 void
pgwin32_dispatch_queued_signals(void)107 pgwin32_dispatch_queued_signals(void)
108 {
109 int exec_mask;
110
111 EnterCriticalSection(&pg_signal_crit_sec);
112 while ((exec_mask = UNBLOCKED_SIGNAL_QUEUE()) != 0)
113 {
114 /* One or more unblocked signals queued for execution */
115 int i;
116
117 for (i = 1; i < PG_SIGNAL_COUNT; i++)
118 {
119 if (exec_mask & sigmask(i))
120 {
121 /* Execute this signal */
122 pqsigfunc sig = pg_signal_array[i];
123
124 if (sig == SIG_DFL)
125 sig = pg_signal_defaults[i];
126 pg_signal_queue &= ~sigmask(i);
127 if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
128 {
129 LeaveCriticalSection(&pg_signal_crit_sec);
130 sig(i);
131 EnterCriticalSection(&pg_signal_crit_sec);
132 break; /* Restart outer loop, in case signal mask or
133 * queue has been modified inside signal
134 * handler */
135 }
136 }
137 }
138 }
139 ResetEvent(pgwin32_signal_event);
140 LeaveCriticalSection(&pg_signal_crit_sec);
141 }
142
143 /* signal masking. Only called on main thread, no sync required */
144 int
pqsigsetmask(int mask)145 pqsigsetmask(int mask)
146 {
147 int prevmask;
148
149 prevmask = pg_signal_mask;
150 pg_signal_mask = mask;
151
152 /*
153 * Dispatch any signals queued up right away, in case we have unblocked
154 * one or more signals previously queued
155 */
156 pgwin32_dispatch_queued_signals();
157
158 return prevmask;
159 }
160
161
162 /*
163 * Unix-like signal handler installation
164 *
165 * Only called on main thread, no sync required
166 */
167 pqsigfunc
pqsignal(int signum,pqsigfunc handler)168 pqsignal(int signum, pqsigfunc handler)
169 {
170 pqsigfunc prevfunc;
171
172 if (signum >= PG_SIGNAL_COUNT || signum < 0)
173 return SIG_ERR;
174 prevfunc = pg_signal_array[signum];
175 pg_signal_array[signum] = handler;
176 return prevfunc;
177 }
178
179 /* Create the signal listener pipe for specified PID */
180 HANDLE
pgwin32_create_signal_listener(pid_t pid)181 pgwin32_create_signal_listener(pid_t pid)
182 {
183 char pipename[128];
184 HANDLE pipe;
185
186 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
187
188 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
189 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
190 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
191
192 if (pipe == INVALID_HANDLE_VALUE)
193 ereport(ERROR,
194 (errmsg("could not create signal listener pipe for PID %d: error code %lu",
195 (int) pid, GetLastError())));
196
197 return pipe;
198 }
199
200
201 /*
202 * All functions below execute on the signal handler thread
203 * and must be synchronized as such!
204 * NOTE! The only global variable that can be used is
205 * pg_signal_queue!
206 */
207
208
209 /*
210 * Queue a signal for the main thread, by setting the flag bit and event.
211 */
212 void
pg_queue_signal(int signum)213 pg_queue_signal(int signum)
214 {
215 if (signum >= PG_SIGNAL_COUNT || signum <= 0)
216 return; /* ignore any bad signal number */
217
218 EnterCriticalSection(&pg_signal_crit_sec);
219 pg_signal_queue |= sigmask(signum);
220 LeaveCriticalSection(&pg_signal_crit_sec);
221
222 SetEvent(pgwin32_signal_event);
223 }
224
225 /*
226 * Signal dispatching thread. This runs after we have received a named
227 * pipe connection from a client (signal sender). Process the request,
228 * close the pipe, and exit.
229 */
230 static DWORD WINAPI
pg_signal_dispatch_thread(LPVOID param)231 pg_signal_dispatch_thread(LPVOID param)
232 {
233 HANDLE pipe = (HANDLE) param;
234 BYTE sigNum;
235 DWORD bytes;
236
237 if (!ReadFile(pipe, &sigNum, 1, &bytes, NULL))
238 {
239 /* Client died before sending */
240 CloseHandle(pipe);
241 return 0;
242 }
243 if (bytes != 1)
244 {
245 /* Received <bytes> bytes over signal pipe (should be 1) */
246 CloseHandle(pipe);
247 return 0;
248 }
249
250 /*
251 * Queue the signal before responding to the client. In this way, it's
252 * guaranteed that once kill() has returned in the signal sender, the next
253 * CHECK_FOR_INTERRUPTS() in the signal recipient will see the signal.
254 * (This is a stronger guarantee than POSIX makes; maybe we don't need it?
255 * But without it, we've seen timing bugs on Windows that do not manifest
256 * on any known Unix.)
257 */
258 pg_queue_signal(sigNum);
259
260 /*
261 * Write something back to the client, allowing its CallNamedPipe() call
262 * to terminate.
263 */
264 WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it works or
265 * not.. */
266
267 /*
268 * We must wait for the client to read the data before we can close the
269 * pipe, else the data will be lost. (If the WriteFile call failed,
270 * there'll be nothing in the buffer, so this shouldn't block.)
271 */
272 FlushFileBuffers(pipe);
273
274 /* This is a formality, since we're about to close the pipe anyway. */
275 DisconnectNamedPipe(pipe);
276
277 /* And we're done. */
278 CloseHandle(pipe);
279
280 return 0;
281 }
282
283 /* Signal handling thread */
284 static DWORD WINAPI
pg_signal_thread(LPVOID param)285 pg_signal_thread(LPVOID param)
286 {
287 char pipename[128];
288 HANDLE pipe = pgwin32_initial_signal_pipe;
289
290 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
291
292 for (;;)
293 {
294 BOOL fConnected;
295 HANDLE hThread;
296
297 /* Create a new pipe instance if we don't have one. */
298 if (pipe == INVALID_HANDLE_VALUE)
299 {
300 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
301 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
302 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
303
304 if (pipe == INVALID_HANDLE_VALUE)
305 {
306 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
307 SleepEx(500, FALSE);
308 continue;
309 }
310 }
311
312 /*
313 * Wait for a client to connect. If something connects before we
314 * reach here, we'll get back a "failure" with ERROR_PIPE_CONNECTED,
315 * which is actually a success (way to go, Microsoft).
316 */
317 fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
318 if (fConnected)
319 {
320 HANDLE newpipe;
321
322 /*
323 * We have a connected pipe. Pass this off to a separate thread
324 * that will do the actual processing of the pipe.
325 *
326 * We must also create a new instance of the pipe *before* we
327 * start running the new thread. If we don't, there is a race
328 * condition whereby the dispatch thread might run CloseHandle()
329 * before we have created a new instance, thereby causing a small
330 * window of time where we will miss incoming requests.
331 */
332 newpipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
333 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
334 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
335 if (newpipe == INVALID_HANDLE_VALUE)
336 {
337 /*
338 * This really should never fail. Just retry in case it does,
339 * even though we have a small race window in that case. There
340 * is nothing else we can do other than abort the whole
341 * process which will be even worse.
342 */
343 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
344
345 /*
346 * Keep going so we at least dispatch this signal. Hopefully,
347 * the call will succeed when retried in the loop soon after.
348 */
349 }
350 hThread = CreateThread(NULL, 0,
351 (LPTHREAD_START_ROUTINE) pg_signal_dispatch_thread,
352 (LPVOID) pipe, 0, NULL);
353 if (hThread == INVALID_HANDLE_VALUE)
354 write_stderr("could not create signal dispatch thread: error code %lu\n",
355 GetLastError());
356 else
357 CloseHandle(hThread);
358
359 /*
360 * Background thread is running with our instance of the pipe. So
361 * replace our reference with the newly created one and loop back
362 * up for another run.
363 */
364 pipe = newpipe;
365 }
366 else
367 {
368 /*
369 * Connection failed. Cleanup and try again.
370 *
371 * This should never happen. If it does, we have a small race
372 * condition until we loop up and re-create the pipe.
373 */
374 CloseHandle(pipe);
375 pipe = INVALID_HANDLE_VALUE;
376 }
377 }
378 return 0;
379 }
380
381
382 /* Console control handler will execute on a thread created
383 by the OS at the time of invocation */
384 static BOOL WINAPI
pg_console_handler(DWORD dwCtrlType)385 pg_console_handler(DWORD dwCtrlType)
386 {
387 if (dwCtrlType == CTRL_C_EVENT ||
388 dwCtrlType == CTRL_BREAK_EVENT ||
389 dwCtrlType == CTRL_CLOSE_EVENT ||
390 dwCtrlType == CTRL_SHUTDOWN_EVENT)
391 {
392 pg_queue_signal(SIGINT);
393 return TRUE;
394 }
395 return FALSE;
396 }
397