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