1 /*-------------------------------------------------------------------------
2  *
3  * signal.c
4  *	  Microsoft Windows Win32 Signal Emulation Functions
5  *
6  * Portions Copyright (c) 1996-2021, 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 	Assert(pgwin32_signal_event != NULL);
56 	if (WaitForSingleObject(pgwin32_signal_event,
57 							(microsec < 500 ? 1 : (microsec + 500) / 1000))
58 		== WAIT_OBJECT_0)
59 	{
60 		pgwin32_dispatch_queued_signals();
61 		errno = EINTR;
62 		return;
63 	}
64 }
65 
66 
67 /* Initialization */
68 void
pgwin32_signal_initialize(void)69 pgwin32_signal_initialize(void)
70 {
71 	int			i;
72 	HANDLE		signal_thread_handle;
73 
74 	InitializeCriticalSection(&pg_signal_crit_sec);
75 
76 	for (i = 0; i < PG_SIGNAL_COUNT; i++)
77 	{
78 		pg_signal_array[i] = SIG_DFL;
79 		pg_signal_defaults[i] = SIG_IGN;
80 	}
81 	pg_signal_mask = 0;
82 	pg_signal_queue = 0;
83 
84 	/* Create the global event handle used to flag signals */
85 	pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
86 	if (pgwin32_signal_event == NULL)
87 		ereport(FATAL,
88 				(errmsg_internal("could not create signal event: error code %lu", GetLastError())));
89 
90 	/* Create thread for handling signals */
91 	signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
92 	if (signal_thread_handle == NULL)
93 		ereport(FATAL,
94 				(errmsg_internal("could not create signal handler thread")));
95 
96 	/* Create console control handle to pick up Ctrl-C etc */
97 	if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
98 		ereport(FATAL,
99 				(errmsg_internal("could not set console control handler")));
100 }
101 
102 /*
103  * Dispatch all signals currently queued and not blocked
104  * Blocked signals are ignored, and will be fired at the time of
105  * the pqsigsetmask() call.
106  */
107 void
pgwin32_dispatch_queued_signals(void)108 pgwin32_dispatch_queued_signals(void)
109 {
110 	int			exec_mask;
111 
112 	Assert(pgwin32_signal_event != NULL);
113 	EnterCriticalSection(&pg_signal_crit_sec);
114 	while ((exec_mask = UNBLOCKED_SIGNAL_QUEUE()) != 0)
115 	{
116 		/* One or more unblocked signals queued for execution */
117 		int			i;
118 
119 		for (i = 1; i < PG_SIGNAL_COUNT; i++)
120 		{
121 			if (exec_mask & sigmask(i))
122 			{
123 				/* Execute this signal */
124 				pqsigfunc	sig = pg_signal_array[i];
125 
126 				if (sig == SIG_DFL)
127 					sig = pg_signal_defaults[i];
128 				pg_signal_queue &= ~sigmask(i);
129 				if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
130 				{
131 					LeaveCriticalSection(&pg_signal_crit_sec);
132 					sig(i);
133 					EnterCriticalSection(&pg_signal_crit_sec);
134 					break;		/* Restart outer loop, in case signal mask or
135 								 * queue has been modified inside signal
136 								 * handler */
137 				}
138 			}
139 		}
140 	}
141 	ResetEvent(pgwin32_signal_event);
142 	LeaveCriticalSection(&pg_signal_crit_sec);
143 }
144 
145 /* signal masking. Only called on main thread, no sync required */
146 int
pqsigsetmask(int mask)147 pqsigsetmask(int mask)
148 {
149 	int			prevmask;
150 
151 	prevmask = pg_signal_mask;
152 	pg_signal_mask = mask;
153 
154 	/*
155 	 * Dispatch any signals queued up right away, in case we have unblocked
156 	 * one or more signals previously queued
157 	 */
158 	pgwin32_dispatch_queued_signals();
159 
160 	return prevmask;
161 }
162 
163 
164 /*
165  * Unix-like signal handler installation
166  *
167  * Only called on main thread, no sync required
168  */
169 pqsigfunc
pqsignal(int signum,pqsigfunc handler)170 pqsignal(int signum, pqsigfunc handler)
171 {
172 	pqsigfunc	prevfunc;
173 
174 	if (signum >= PG_SIGNAL_COUNT || signum < 0)
175 		return SIG_ERR;
176 	prevfunc = pg_signal_array[signum];
177 	pg_signal_array[signum] = handler;
178 	return prevfunc;
179 }
180 
181 /* Create the signal listener pipe for specified PID */
182 HANDLE
pgwin32_create_signal_listener(pid_t pid)183 pgwin32_create_signal_listener(pid_t pid)
184 {
185 	char		pipename[128];
186 	HANDLE		pipe;
187 
188 	snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
189 
190 	pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
191 						   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
192 						   PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
193 
194 	if (pipe == INVALID_HANDLE_VALUE)
195 		ereport(ERROR,
196 				(errmsg("could not create signal listener pipe for PID %d: error code %lu",
197 						(int) pid, GetLastError())));
198 
199 	return pipe;
200 }
201 
202 
203 /*
204  * All functions below execute on the signal handler thread
205  * and must be synchronized as such!
206  * NOTE! The only global variable that can be used is
207  * pg_signal_queue!
208  */
209 
210 
211 /*
212  * Queue a signal for the main thread, by setting the flag bit and event.
213  */
214 void
pg_queue_signal(int signum)215 pg_queue_signal(int signum)
216 {
217 	Assert(pgwin32_signal_event != NULL);
218 	if (signum >= PG_SIGNAL_COUNT || signum <= 0)
219 		return;					/* ignore any bad signal number */
220 
221 	EnterCriticalSection(&pg_signal_crit_sec);
222 	pg_signal_queue |= sigmask(signum);
223 	LeaveCriticalSection(&pg_signal_crit_sec);
224 
225 	SetEvent(pgwin32_signal_event);
226 }
227 
228 /* Signal handling thread */
229 static DWORD WINAPI
pg_signal_thread(LPVOID param)230 pg_signal_thread(LPVOID param)
231 {
232 	char		pipename[128];
233 	HANDLE		pipe = pgwin32_initial_signal_pipe;
234 
235 	/* Set up pipe name, in case we have to re-create the pipe. */
236 	snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
237 
238 	for (;;)
239 	{
240 		BOOL		fConnected;
241 
242 		/* Create a new pipe instance if we don't have one. */
243 		if (pipe == INVALID_HANDLE_VALUE)
244 		{
245 			pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
246 								   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
247 								   PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
248 
249 			if (pipe == INVALID_HANDLE_VALUE)
250 			{
251 				write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
252 				SleepEx(500, FALSE);
253 				continue;
254 			}
255 		}
256 
257 		/*
258 		 * Wait for a client to connect.  If something connects before we
259 		 * reach here, we'll get back a "failure" with ERROR_PIPE_CONNECTED,
260 		 * which is actually a success (way to go, Microsoft).
261 		 */
262 		fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
263 		if (fConnected)
264 		{
265 			/*
266 			 * We have a connection from a would-be signal sender. Process it.
267 			 */
268 			BYTE		sigNum;
269 			DWORD		bytes;
270 
271 			if (ReadFile(pipe, &sigNum, 1, &bytes, NULL) &&
272 				bytes == 1)
273 			{
274 				/*
275 				 * Queue the signal before responding to the client.  In this
276 				 * way, it's guaranteed that once kill() has returned in the
277 				 * signal sender, the next CHECK_FOR_INTERRUPTS() in the
278 				 * signal recipient will see the signal.  (This is a stronger
279 				 * guarantee than POSIX makes; maybe we don't need it?  But
280 				 * without it, we've seen timing bugs on Windows that do not
281 				 * manifest on any known Unix.)
282 				 */
283 				pg_queue_signal(sigNum);
284 
285 				/*
286 				 * Write something back to the client, allowing its
287 				 * CallNamedPipe() call to terminate.
288 				 */
289 				WriteFile(pipe, &sigNum, 1, &bytes, NULL);	/* Don't care if it
290 															 * works or not */
291 
292 				/*
293 				 * We must wait for the client to read the data before we can
294 				 * disconnect, else the data will be lost.  (If the WriteFile
295 				 * call failed, there'll be nothing in the buffer, so this
296 				 * shouldn't block.)
297 				 */
298 				FlushFileBuffers(pipe);
299 			}
300 			else
301 			{
302 				/*
303 				 * If we fail to read a byte from the client, assume it's the
304 				 * client's problem and do nothing.  Perhaps it'd be better to
305 				 * force a pipe close and reopen?
306 				 */
307 			}
308 
309 			/* Disconnect from client so that we can re-use the pipe. */
310 			DisconnectNamedPipe(pipe);
311 		}
312 		else
313 		{
314 			/*
315 			 * Connection failed.  Cleanup and try again.
316 			 *
317 			 * This should never happen.  If it does, there's a window where
318 			 * we'll miss signals until we manage to re-create the pipe.
319 			 * However, just trying to use the same pipe again is probably not
320 			 * going to work, so we have little choice.
321 			 */
322 			CloseHandle(pipe);
323 			pipe = INVALID_HANDLE_VALUE;
324 		}
325 	}
326 	return 0;
327 }
328 
329 
330 /* Console control handler will execute on a thread created
331    by the OS at the time of invocation */
332 static BOOL WINAPI
pg_console_handler(DWORD dwCtrlType)333 pg_console_handler(DWORD dwCtrlType)
334 {
335 	if (dwCtrlType == CTRL_C_EVENT ||
336 		dwCtrlType == CTRL_BREAK_EVENT ||
337 		dwCtrlType == CTRL_CLOSE_EVENT ||
338 		dwCtrlType == CTRL_SHUTDOWN_EVENT)
339 	{
340 		pg_queue_signal(SIGINT);
341 		return TRUE;
342 	}
343 	return FALSE;
344 }
345