Skip to content

Commit b28ac1d

Browse files
committed
Provide sigaction() for Windows.
Commit 9abb2bf left behind code to block signals inside signal handlers on Windows, because our signal porting layer didn't have sigaction(). Provide a minimal implementation that is capable of blocking signals, to get rid of platform differences. See also related commit c94ae9d. Discussion: https://postgr.es/m/CA%2BhUKGKKKfcgx6jzok9AYenp2TNti_tfs8FMoJpL8%2B0Gsy%3D%3D_A%40mail.gmail.com
1 parent 6bbd8b7 commit b28ac1d

File tree

5 files changed

+53
-79
lines changed

5 files changed

+53
-79
lines changed

src/backend/libpq/pqsignal.c

-9
Original file line numberDiff line numberDiff line change
@@ -110,16 +110,10 @@ pqinitmask(void)
110110
* postmaster ever unblocks signals.
111111
*
112112
* pqinitmask() must have been invoked previously.
113-
*
114-
* On Windows, this function is just an alias for pqsignal()
115-
* (and note that it's calling the code in src/backend/port/win32/signal.c,
116-
* not src/port/pqsignal.c). On that platform, the postmaster's signal
117-
* handlers still have to block signals for themselves.
118113
*/
119114
pqsigfunc
120115
pqsignal_pm(int signo, pqsigfunc func)
121116
{
122-
#ifndef WIN32
123117
struct sigaction act,
124118
oact;
125119

@@ -142,7 +136,4 @@ pqsignal_pm(int signo, pqsigfunc func)
142136
if (sigaction(signo, &act, &oact) < 0)
143137
return SIG_ERR;
144138
return oact.sa_handler;
145-
#else /* WIN32 */
146-
return pqsignal(signo, func);
147-
#endif
148139
}

src/backend/port/win32/signal.c

+29-12
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ HANDLE pgwin32_initial_signal_pipe = INVALID_HANDLE_VALUE;
3434
static CRITICAL_SECTION pg_signal_crit_sec;
3535

3636
/* Note that array elements 0 are unused since they correspond to signal 0 */
37-
static pqsigfunc pg_signal_array[PG_SIGNAL_COUNT];
37+
static struct sigaction pg_signal_array[PG_SIGNAL_COUNT];
3838
static pqsigfunc pg_signal_defaults[PG_SIGNAL_COUNT];
3939

4040

@@ -85,7 +85,9 @@ pgwin32_signal_initialize(void)
8585

8686
for (i = 0; i < PG_SIGNAL_COUNT; i++)
8787
{
88-
pg_signal_array[i] = SIG_DFL;
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;
8991
pg_signal_defaults[i] = SIG_IGN;
9092
}
9193
pg_signal_mask = 0;
@@ -131,15 +133,27 @@ pgwin32_dispatch_queued_signals(void)
131133
if (exec_mask & sigmask(i))
132134
{
133135
/* Execute this signal */
134-
pqsigfunc sig = pg_signal_array[i];
136+
struct sigaction *act = &pg_signal_array[i];
137+
pqsigfunc sig = act->sa_handler;
135138

136139
if (sig == SIG_DFL)
137140
sig = pg_signal_defaults[i];
138141
pg_signal_queue &= ~sigmask(i);
139142
if (sig != SIG_ERR && sig != SIG_IGN && sig != SIG_DFL)
140143
{
144+
sigset_t block_mask;
145+
sigset_t save_mask;
146+
141147
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);
142154
sig(i);
155+
sigprocmask(SIG_SETMASK, &save_mask, NULL);
156+
143157
EnterCriticalSection(&pg_signal_crit_sec);
144158
break; /* Restart outer loop, in case signal mask or
145159
* queue has been modified inside signal
@@ -187,22 +201,25 @@ pqsigprocmask(int how, const sigset_t *set, sigset_t *oset)
187201
return 0;
188202
}
189203

190-
191204
/*
192205
* Unix-like signal handler installation
193206
*
194207
* Only called on main thread, no sync required
195208
*/
196-
pqsigfunc
197-
pqsignal(int signum, pqsigfunc handler)
209+
int
210+
pqsigaction(int signum, const struct sigaction *act,
211+
struct sigaction *oldact)
198212
{
199-
pqsigfunc prevfunc;
200-
201213
if (signum >= PG_SIGNAL_COUNT || signum < 0)
202-
return SIG_ERR;
203-
prevfunc = pg_signal_array[signum];
204-
pg_signal_array[signum] = handler;
205-
return prevfunc;
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;
206223
}
207224

208225
/* Create the signal listener pipe for specified PID */

src/backend/postmaster/postmaster.c

+4-53
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,10 @@ PostmasterMain(int argc, char *argv[])
620620
* is used by all child processes and client processes). That has a
621621
* couple of special behaviors:
622622
*
623-
* 1. Except on Windows, we tell sigaction() to block all signals for the
624-
* duration of the signal handler. This is faster than our old approach
625-
* of blocking/unblocking explicitly in the signal handler, and it should
626-
* also prevent excessive stack consumption if signals arrive quickly.
623+
* 1. We tell sigaction() to block all signals for the duration of the
624+
* signal handler. This is faster than our old approach of
625+
* blocking/unblocking explicitly in the signal handler, and it should also
626+
* prevent excessive stack consumption if signals arrive quickly.
627627
*
628628
* 2. We do not set the SA_RESTART flag. This is because signals will be
629629
* blocked at all times except when ServerLoop is waiting for something to
@@ -2726,14 +2726,6 @@ SIGHUP_handler(SIGNAL_ARGS)
27262726
{
27272727
int save_errno = errno;
27282728

2729-
/*
2730-
* We rely on the signal mechanism to have blocked all signals ... except
2731-
* on Windows, which lacks sigaction(), so we have to do it manually.
2732-
*/
2733-
#ifdef WIN32
2734-
PG_SETMASK(&BlockSig);
2735-
#endif
2736-
27372729
if (Shutdown <= SmartShutdown)
27382730
{
27392731
ereport(LOG,
@@ -2790,10 +2782,6 @@ SIGHUP_handler(SIGNAL_ARGS)
27902782
#endif
27912783
}
27922784

2793-
#ifdef WIN32
2794-
PG_SETMASK(&UnBlockSig);
2795-
#endif
2796-
27972785
errno = save_errno;
27982786
}
27992787

@@ -2806,14 +2794,6 @@ pmdie(SIGNAL_ARGS)
28062794
{
28072795
int save_errno = errno;
28082796

2809-
/*
2810-
* We rely on the signal mechanism to have blocked all signals ... except
2811-
* on Windows, which lacks sigaction(), so we have to do it manually.
2812-
*/
2813-
#ifdef WIN32
2814-
PG_SETMASK(&BlockSig);
2815-
#endif
2816-
28172797
ereport(DEBUG2,
28182798
(errmsg_internal("postmaster received signal %d",
28192799
postgres_signal_arg)));
@@ -2938,10 +2918,6 @@ pmdie(SIGNAL_ARGS)
29382918
break;
29392919
}
29402920

2941-
#ifdef WIN32
2942-
PG_SETMASK(&UnBlockSig);
2943-
#endif
2944-
29452921
errno = save_errno;
29462922
}
29472923

@@ -2955,14 +2931,6 @@ reaper(SIGNAL_ARGS)
29552931
int pid; /* process id of dead child process */
29562932
int exitstatus; /* its exit status */
29572933

2958-
/*
2959-
* We rely on the signal mechanism to have blocked all signals ... except
2960-
* on Windows, which lacks sigaction(), so we have to do it manually.
2961-
*/
2962-
#ifdef WIN32
2963-
PG_SETMASK(&BlockSig);
2964-
#endif
2965-
29662934
ereport(DEBUG4,
29672935
(errmsg_internal("reaping dead processes")));
29682936

@@ -3255,11 +3223,6 @@ reaper(SIGNAL_ARGS)
32553223
*/
32563224
PostmasterStateMachine();
32573225

3258-
/* Done with signal handler */
3259-
#ifdef WIN32
3260-
PG_SETMASK(&UnBlockSig);
3261-
#endif
3262-
32633226
errno = save_errno;
32643227
}
32653228

@@ -5106,14 +5069,6 @@ sigusr1_handler(SIGNAL_ARGS)
51065069
{
51075070
int save_errno = errno;
51085071

5109-
/*
5110-
* We rely on the signal mechanism to have blocked all signals ... except
5111-
* on Windows, which lacks sigaction(), so we have to do it manually.
5112-
*/
5113-
#ifdef WIN32
5114-
PG_SETMASK(&BlockSig);
5115-
#endif
5116-
51175072
/*
51185073
* RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in
51195074
* unexpected states. If the startup process quickly starts up, completes
@@ -5254,10 +5209,6 @@ sigusr1_handler(SIGNAL_ARGS)
52545209
signal_child(StartupPID, SIGUSR2);
52555210
}
52565211

5257-
#ifdef WIN32
5258-
PG_SETMASK(&UnBlockSig);
5259-
#endif
5260-
52615212
errno = save_errno;
52625213
}
52635214

src/include/libpq/pqsignal.h

+14
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,26 @@
2121
/* Emulate POSIX sigset_t APIs on Windows */
2222
typedef int sigset_t;
2323

24+
#define SA_RESTART 1
25+
#define SA_NODEFER 2
26+
27+
struct sigaction
28+
{
29+
void (*sa_handler) (int);
30+
/* sa_sigaction not yet implemented */
31+
sigset_t sa_mask;
32+
int sa_flags;
33+
};
34+
2435
extern int pqsigprocmask(int how, const sigset_t *set, sigset_t *oset);
36+
extern int pqsigaction(int signum, const struct sigaction *act,
37+
struct sigaction *oldact);
2538

2639
#define SIG_BLOCK 1
2740
#define SIG_UNBLOCK 2
2841
#define SIG_SETMASK 3
2942
#define sigprocmask(how, set, oset) pqsigprocmask((how), (set), (oset))
43+
#define sigaction(signum, act, oldact) pqsigaction((signum), (act), (oldact))
3044
#define sigemptyset(set) (*(set) = 0)
3145
#define sigfillset(set) (*(set) = ~0)
3246
#define sigaddset(set, signum) (*(set) |= (sigmask(signum)))

src/port/pqsignal.c

+6-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929

3030
#include <signal.h>
3131

32-
#if !defined(WIN32) || defined(FRONTEND)
32+
#ifndef FRONTEND
33+
#include "libpq/pqsignal.h"
34+
#endif
3335

3436
/*
3537
* Set up a signal handler, with SA_RESTART, for signal "signo"
@@ -39,7 +41,7 @@
3941
pqsigfunc
4042
pqsignal(int signo, pqsigfunc func)
4143
{
42-
#ifndef WIN32
44+
#if !(defined(WIN32) && defined(FRONTEND))
4345
struct sigaction act,
4446
oact;
4547

@@ -53,9 +55,8 @@ pqsignal(int signo, pqsigfunc func)
5355
if (sigaction(signo, &act, &oact) < 0)
5456
return SIG_ERR;
5557
return oact.sa_handler;
56-
#else /* WIN32 */
58+
#else
59+
/* Forward to Windows native signal system. */
5760
return signal(signo, func);
5861
#endif
5962
}
60-
61-
#endif /* !defined(WIN32) || defined(FRONTEND) */

0 commit comments

Comments
 (0)