PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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
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 */
35
36/* Note that array elements 0 are unused since they correspond to signal 0 */
39
40
41/* Signal handling thread functions */
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
54{
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
67 (microsec < 500 ? 1 : (microsec + 500) / 1000))
69 {
71 errno = EINTR;
72 return;
73 }
74}
75
76
77/* Initialization */
78void
80{
81 int i;
83
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 */
100 (errmsg_internal("could not create signal event: error code %lu", GetLastError())));
101
102 /* Create thread for handling signals */
106 (errmsg_internal("could not create signal handler thread")));
107
108 /* Create console control handle to pick up Ctrl-C etc */
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
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 = (pqsigfunc) (pg_funcptr_t) act->sa_handler;
138
139 if (sig == PG_SIG_DFL)
143 {
146 struct pg_signal_info nodata;
147
148 nodata.pid = 0;
149 nodata.uid = 0;
150
152
153 block_mask = act->sa_mask;
154 if ((act->sa_flags & SA_NODEFER) == 0)
155 block_mask |= sigmask(i);
156
158 sig(i, &nodata);
160
162 break; /* Restart outer loop, in case signal mask or
163 * queue has been modified inside signal
164 * handler */
165 }
166 }
167 }
168 }
171}
172
173/* signal masking. Only called on main thread, no sync required */
174int
176{
177 if (oset)
179
180 if (!set)
181 return 0;
182
183 switch (how)
184 {
185 case SIG_BLOCK:
186 pg_signal_mask |= *set;
187 break;
188 case SIG_UNBLOCK:
189 pg_signal_mask &= ~*set;
190 break;
191 case SIG_SETMASK:
192 pg_signal_mask = *set;
193 break;
194 default:
195 errno = EINVAL;
196 return -1;
197 }
198
199 /*
200 * Dispatch any signals queued up right away, in case we have unblocked
201 * one or more signals previously queued
202 */
204
205 return 0;
206}
207
208/*
209 * Unix-like signal handler installation
210 *
211 * Only called on main thread, no sync required
212 */
213int
214pqsigaction(int signum, const struct sigaction *act,
215 struct sigaction *oldact)
216{
217 if (signum >= PG_SIGNAL_COUNT || signum < 0)
218 {
219 errno = EINVAL;
220 return -1;
221 }
222 if (oldact)
224 if (act)
226 return 0;
227}
228
229/* Create the signal listener pipe for specified PID */
230HANDLE
232{
233 char pipename[128];
234 HANDLE pipe;
235
236 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%u", (int) pid);
237
240 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
241
242 if (pipe == INVALID_HANDLE_VALUE)
244 (errmsg("could not create signal listener pipe for PID %d: error code %lu",
245 (int) pid, GetLastError())));
246
247 return pipe;
248}
249
250
251/*
252 * All functions below execute on the signal handler thread
253 * and must be synchronized as such!
254 * NOTE! The only global variable that can be used is
255 * pg_signal_queue!
256 */
257
258
259/*
260 * Queue a signal for the main thread, by setting the flag bit and event.
261 */
262void
264{
266 if (signum >= PG_SIGNAL_COUNT || signum <= 0)
267 return; /* ignore any bad signal number */
268
272
274}
275
276/* Signal handling thread */
277static DWORD WINAPI
279{
280 char pipename[128];
282
283 /* Set up pipe name, in case we have to re-create the pipe. */
284 snprintf(pipename, sizeof(pipename), "\\\\.\\pipe\\pgsignal_%lu", GetCurrentProcessId());
285
286 for (;;)
287 {
289
290 /* Create a new pipe instance if we don't have one. */
291 if (pipe == INVALID_HANDLE_VALUE)
292 {
295 PIPE_UNLIMITED_INSTANCES, 16, 16, 1000, NULL);
296
297 if (pipe == INVALID_HANDLE_VALUE)
298 {
299 write_stderr("could not create signal listener pipe: error code %lu; retrying\n", GetLastError());
300 SleepEx(500, FALSE);
301 continue;
302 }
303 }
304
305 /*
306 * Wait for a client to connect. If something connects before we
307 * reach here, we'll get back a "failure" with ERROR_PIPE_CONNECTED,
308 * which is actually a success (way to go, Microsoft).
309 */
311 if (fConnected)
312 {
313 /*
314 * We have a connection from a would-be signal sender. Process it.
315 */
316 BYTE sigNum;
317 DWORD bytes;
318
319 if (ReadFile(pipe, &sigNum, 1, &bytes, NULL) &&
320 bytes == 1)
321 {
322 /*
323 * Queue the signal before responding to the client. In this
324 * way, it's guaranteed that once kill() has returned in the
325 * signal sender, the next CHECK_FOR_INTERRUPTS() in the
326 * signal recipient will see the signal. (This is a stronger
327 * guarantee than POSIX makes; maybe we don't need it? But
328 * without it, we've seen timing bugs on Windows that do not
329 * manifest on any known Unix.)
330 */
332
333 /*
334 * Write something back to the client, allowing its
335 * CallNamedPipe() call to terminate.
336 */
337 WriteFile(pipe, &sigNum, 1, &bytes, NULL); /* Don't care if it
338 * works or not */
339
340 /*
341 * We must wait for the client to read the data before we can
342 * disconnect, else the data will be lost. (If the WriteFile
343 * call failed, there'll be nothing in the buffer, so this
344 * shouldn't block.)
345 */
346 FlushFileBuffers(pipe);
347 }
348 else
349 {
350 /*
351 * If we fail to read a byte from the client, assume it's the
352 * client's problem and do nothing. Perhaps it'd be better to
353 * force a pipe close and reopen?
354 */
355 }
356
357 /* Disconnect from client so that we can re-use the pipe. */
359 }
360 else
361 {
362 /*
363 * Connection failed. Cleanup and try again.
364 *
365 * This should never happen. If it does, there's a window where
366 * we'll miss signals until we manage to re-create the pipe.
367 * However, just trying to use the same pipe again is probably not
368 * going to work, so we have little choice.
369 */
370 CloseHandle(pipe);
372 }
373 }
374 return 0;
375}
376
377
378/* Console control handler will execute on a thread created
379 by the OS at the time of invocation */
380static BOOL WINAPI
#define write_stderr(str)
Definition parallel.c:186
#define Assert(condition)
Definition c.h:943
#define unlikely(x)
Definition c.h:438
void(* pg_funcptr_t)(void)
Definition c.h:548
#define FATAL
Definition elog.h:42
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
int i
Definition isn.c:77
static char * errmsg
static int sig
Definition pg_ctl.c:81
void(* pqsigfunc)(SIGNAL_ARGS)
Definition port.h:552
#define PG_SIG_IGN
Definition port.h:551
#define snprintf
Definition port.h:260
#define PG_SIG_DFL
Definition port.h:550
static int fb(int x)
HANDLE pgwin32_create_signal_listener(pid_t pid)
Definition signal.c:231
static DWORD WINAPI pg_signal_thread(LPVOID param)
Definition signal.c:278
int pqsigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
Definition signal.c:214
static struct sigaction pg_signal_array[PG_SIGNAL_COUNT]
Definition signal.c:37
void pg_queue_signal(int signum)
Definition signal.c:263
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:381
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:175
void pgwin32_signal_initialize(void)
Definition signal.c:79
int pg_signal_mask
Definition signal.c:25
uint32_t pid
Definition c.h:1449
#define UNBLOCKED_SIGNAL_QUEUE()
Definition win32_port.h:481
#define EINTR
Definition win32_port.h:361
#define sigmask(sig)
Definition win32_port.h:155
#define PG_SIGNAL_COUNT
Definition win32_port.h:482