PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
signal.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * signal.c
4 * Microsoft Windows Win32 Signal Emulation Functions
5 *
6 * Portions Copyright (c) 1996-2024, 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 */
24volatile int pg_signal_queue;
26
28HANDLE 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 */
34static CRITICAL_SECTION pg_signal_crit_sec;
35
36/* Note that array elements 0 are unused since they correspond to signal 0 */
37static struct sigaction pg_signal_array[PG_SIGNAL_COUNT];
39
40
41/* Signal handling thread functions */
42static DWORD WINAPI pg_signal_thread(LPVOID param);
43static 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 */
52void
53pg_usleep(long microsec)
54{
55 if (unlikely(pgwin32_signal_event == NULL))
56 {
57 /*
58 * If we're reached by pgwin32_open_handle() early in startup before
59 * the signal event is set up, just fall back to a regular
60 * non-interruptible sleep.
61 */
62 SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE);
63 return;
64 }
65
66 if (WaitForSingleObject(pgwin32_signal_event,
67 (microsec < 500 ? 1 : (microsec + 500) / 1000))
68 == WAIT_OBJECT_0)
69 {
71 errno = EINTR;
72 return;
73 }
74}
75
76
77/* Initialization */
78void
80{
81 int i;
82 HANDLE signal_thread_handle;
83
84 InitializeCriticalSection(&pg_signal_crit_sec);
85
86 for (i = 0; i < PG_SIGNAL_COUNT; i++)
87 {
88 pg_signal_array[i].sa_handler = SIG_DFL;
89 pg_signal_array[i].sa_mask = 0;
90 pg_signal_array[i].sa_flags = 0;
92 }
95
96 /* Create the global event handle used to flag signals */
97 pgwin32_signal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
98 if (pgwin32_signal_event == NULL)
100 (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
101
102 /* Create thread for handling signals */
103 signal_thread_handle = CreateThread(NULL, 0, pg_signal_thread, NULL, 0, NULL);
104 if (signal_thread_handle == NULL)
106 (errmsg_internal("could not create signal handler thread")));
107
108 /* Create console control handle to pick up Ctrl-C etc */
109 if (!SetConsoleCtrlHandler(pg_console_handler, TRUE))
111 (errmsg_internal("could not set console control handler")));
112}
113
114/*
115 * Dispatch all signals currently queued and not blocked
116 * Blocked signals are ignored, and will be fired at the time of
117 * the pqsigprocmask() call.
118 */
119void
121{
122 int exec_mask;
123
125 EnterCriticalSection(&pg_signal_crit_sec);
126 while ((exec_mask = UNBLOCKED_SIGNAL_QUEUE()) != 0)
127 {
128 /* One or more unblocked signals queued for execution */
129 int i;
130
131 for (i = 1; i < PG_SIGNAL_COUNT; i++)
132 {
133 if (exec_mask & sigmask(i))
134 {
135 /* Execute this signal */
136 struct sigaction *act = &pg_signal_array[i];
137 pqsigfunc sig = act->sa_handler;
138
139 if (sig == SIG_DFL)
141 pg_signal_queue &= ~sigmask(i);
142 if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
143 {
144 sigset_t block_mask;
145 sigset_t save_mask;
146
147 LeaveCriticalSection(&pg_signal_crit_sec);
148
149 block_mask = act->sa_mask;
150 if ((act->sa_flags & SA_NODEFER) == 0)
151 block_mask |= sigmask(i);
152
153 sigprocmask(SIG_BLOCK, &block_mask, &save_mask);
154 sig(i);
155 sigprocmask(SIG_SETMASK, &save_mask, NULL);
156
157 EnterCriticalSection(&pg_signal_crit_sec);
158 break; /* Restart outer loop, in case signal mask or
159 * queue has been modified inside signal
160 * handler */
161 }
162 }
163 }
164 }
165 ResetEvent(pgwin32_signal_event);
166 LeaveCriticalSection(&pg_signal_crit_sec);
167}
168
169/* signal masking. Only called on main thread, no sync required */
170int
171pqsigprocmask(int how, const sigset_t *set, sigset_t *oset)
172{
173 if (oset)
174 *oset = pg_signal_mask;
175
176 if (!set)
177 return 0;
178
179 switch (how)
180 {
181 case SIG_BLOCK:
182 pg_signal_mask |= *set;
183 break;
184 case SIG_UNBLOCK:
185 pg_signal_mask &= ~*set;
186 break;
187 case SIG_SETMASK:
188 pg_signal_mask = *set;
189 break;
190 default:
191 errno = EINVAL;
192 return -1;
193 }
194
195 /*
196 * Dispatch any signals queued up right away, in case we have unblocked
197 * one or more signals previously queued
198 */
200
201 return 0;
202}
203
204/*
205 * Unix-like signal handler installation
206 *
207 * Only called on main thread, no sync required
208 */
209int
210pqsigaction(int signum, const struct sigaction *act,
211 struct sigaction *oldact)
212{
213 if (signum >= PG_SIGNAL_COUNT || signum < 0)
214 {
215 errno = EINVAL;
216 return -1;
217 }
218 if (oldact)
219 *oldact = pg_signal_array[signum];
220 if (act)
221 pg_signal_array[signum] = *act;
222 return 0;
223}
224
225/* Create the signal listener pipe for specified PID */
226HANDLE
228{
229 char pipename[128];
230 HANDLE pipe;
231
232 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
233
234 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
235 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
236 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
237
238 if (pipe == INVALID_HANDLE_VALUE)
240 (errmsg("could not create signal listener pipe for PID %d: error code %lu",
241 (int) pid, GetLastError())));
242
243 return pipe;
244}
245
246
247/*
248 * All functions below execute on the signal handler thread
249 * and must be synchronized as such!
250 * NOTE! The only global variable that can be used is
251 * pg_signal_queue!
252 */
253
254
255/*
256 * Queue a signal for the main thread, by setting the flag bit and event.
257 */
258void
260{
262 if (signum >= PG_SIGNAL_COUNT || signum <= 0)
263 return; /* ignore any bad signal number */
264
265 EnterCriticalSection(&pg_signal_crit_sec);
266 pg_signal_queue |= sigmask(signum);
267 LeaveCriticalSection(&pg_signal_crit_sec);
268
269 SetEvent(pgwin32_signal_event);
270}
271
272/* Signal handling thread */
273static DWORD WINAPI
274pg_signal_thread(LPVOID param)
275{
276 char pipename[128];
277 HANDLE pipe = pgwin32_initial_signal_pipe;
278
279 /* Set up pipe name, in case we have to re-create the pipe. */
280 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
281
282 for (;;)
283 {
284 BOOL fConnected;
285
286 /* Create a new pipe instance if we don't have one. */
287 if (pipe == INVALID_HANDLE_VALUE)
288 {
289 pipe = CreateNamedPipe(pipename, PIPE_ACCESS_DUPLEX,
290 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
291 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
292
293 if (pipe == INVALID_HANDLE_VALUE)
294 {
295 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
296 SleepEx(500, FALSE);
297 continue;
298 }
299 }
300
301 /*
302 * Wait for a client to connect. If something connects before we
303 * reach here, we'll get back a "failure" with ERROR_PIPE_CONNECTED,
304 * which is actually a success (way to go, Microsoft).
305 */
306 fConnected = ConnectNamedPipe(pipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
307 if (fConnected)
308 {
309 /*
310 * We have a connection from a would-be signal sender. Process it.
311 */
312 BYTE sigNum;
313 DWORD bytes;
314
315 if (ReadFile(pipe, &sigNum, 1, &bytes, NULL) &&
316 bytes == 1)
317 {
318 /*
319 * Queue the signal before responding to the client. In this
320 * way, it's guaranteed that once kill() has returned in the
321 * signal sender, the next CHECK_FOR_INTERRUPTS() in the
322 * signal recipient will see the signal. (This is a stronger
323 * guarantee than POSIX makes; maybe we don't need it? But
324 * without it, we've seen timing bugs on Windows that do not
325 * manifest on any known Unix.)
326 */
327 pg_queue_signal(sigNum);
328
329 /*
330 * Write something back to the client, allowing its
331 * CallNamedPipe() call to terminate.
332 */
333 WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it
334 * works or not */
335
336 /*
337 * We must wait for the client to read the data before we can
338 * disconnect, else the data will be lost. (If the WriteFile
339 * call failed, there'll be nothing in the buffer, so this
340 * shouldn't block.)
341 */
342 FlushFileBuffers(pipe);
343 }
344 else
345 {
346 /*
347 * If we fail to read a byte from the client, assume it's the
348 * client's problem and do nothing. Perhaps it'd be better to
349 * force a pipe close and reopen?
350 */
351 }
352
353 /* Disconnect from client so that we can re-use the pipe. */
354 DisconnectNamedPipe(pipe);
355 }
356 else
357 {
358 /*
359 * Connection failed. Cleanup and try again.
360 *
361 * This should never happen. If it does, there's a window where
362 * we'll miss signals until we manage to re-create the pipe.
363 * However, just trying to use the same pipe again is probably not
364 * going to work, so we have little choice.
365 */
366 CloseHandle(pipe);
367 pipe = INVALID_HANDLE_VALUE;
368 }
369 }
370 return 0;
371}
372
373
374/* Console control handler will execute on a thread created
375 by the OS at the time of invocation */
376static BOOL WINAPI
377pg_console_handler(DWORD dwCtrlType)
378{
379 if (dwCtrlType == CTRL_C_EVENT ||
380 dwCtrlType == CTRL_BREAK_EVENT ||
381 dwCtrlType == CTRL_CLOSE_EVENT ||
382 dwCtrlType == CTRL_SHUTDOWN_EVENT)
383 {
384 pg_queue_signal(SIGINT);
385 return TRUE;
386 }
387 return FALSE;
388}
#define write_stderr(str)
Definition: parallel.c:186
#define Assert(condition)
Definition: c.h:812
#define unlikely(x)
Definition: c.h:330
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define FATAL
Definition: elog.h:41
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int i
Definition: isn.c:72
static int sig
Definition: pg_ctl.c:80
void(* pqsigfunc)(SIGNAL_ARGS)
Definition: port.h:490
#define snprintf
Definition: port.h:238
HANDLE pgwin32_create_signal_listener(pid_t pid)
Definition: signal.c:227
static DWORD WINAPI pg_signal_thread(LPVOID param)
Definition: signal.c:274
int pqsigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Definition: signal.c:210
static struct sigaction pg_signal_array[PG_SIGNAL_COUNT]
Definition: signal.c:37
void pg_queue_signal(int signum)
Definition: signal.c:259
void pg_usleep(long microsec)
Definition: signal.c:53
volatile int pg_signal_queue
Definition: signal.c:24
HANDLE pgwin32_initial_signal_pipe
Definition: signal.c:28
static CRITICAL_SECTION pg_signal_crit_sec
Definition: signal.c:34
static BOOL WINAPI pg_console_handler(DWORD dwCtrlType)
Definition: signal.c:377
static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT]
Definition: signal.c:38
void pgwin32_dispatch_queued_signals(void)
Definition: signal.c:120
HANDLE pgwin32_signal_event
Definition: signal.c:27
int pqsigprocmask(int how, const sigset_t *set, sigset_t *oset)
Definition: signal.c:171
void pgwin32_signal_initialize(void)
Definition: signal.c:79
int pg_signal_mask
Definition: signal.c:25
#define UNBLOCKED_SIGNAL_QUEUE()
Definition: win32_port.h:494
#define SIG_DFL
Definition: win32_port.h:163
#define SIG_ERR
Definition: win32_port.h:164
#define EINTR
Definition: win32_port.h:374
#define sigmask(sig)
Definition: win32_port.h:157
#define SIG_IGN
Definition: win32_port.h:165
#define PG_SIGNAL_COUNT
Definition: win32_port.h:495