Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4e95733

Browse files
committed
In the postmaster, rely on the signal infrastructure to block signals.
POSIX sigaction(2) can be told to block a set of signals while asignal handler executes. Make use of that instead of manuallyblocking and unblocking signals in the postmaster's signal handlers.This should save a few cycles, but more importantly it preventsrecursive invocation of signal handlers when many signals arrive inclose succession. (Assuming that the platform's signal infrastructureis designed to avoid consuming stack space in that case, but this isdemonstrably true at least on Linux.) The existing code has been seento recurse to the point of stack overflow, either in the postmasteror in a forked-off child.Back-patch of commit9abb2bf. At the time, we'd only seen excesspostmaster stack consumption in the buildfarm; but we now have auser report of it, and that commit has aged enough to have a fairamount of confidence that it doesn't break anything.This still doesn't change anything about the way that it works onWindows. Perhaps someone else would like to fix that?Per bug #16673 from David Geier. Back-patch to 9.6. Althoughthe problem exists in principle before that, we've only seen itactually materialize in connection with heavy use of parallelworkers, so it doesn't seem necessary to do anything in 9.5;and the relevant code is different there, too.Discussion:https://postgr.es/m/16673-d278c604f8e34ec0@postgresql.orgDiscussion:https://postgr.es/m/14878.1570820201@sss.pgh.pa.us
1 parenta5c77e6 commit4e95733

File tree

5 files changed

+116
-57
lines changed

5 files changed

+116
-57
lines changed

‎src/backend/libpq/pqsignal.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,52 @@ pqinitmask(void)
9595
sigdelset(&StartupBlockSig,SIGALRM);
9696
#endif
9797
}
98+
99+
/*
100+
* Set up a postmaster signal handler for signal "signo"
101+
*
102+
* Returns the previous handler.
103+
*
104+
* This is used only in the postmaster, which has its own odd approach to
105+
* signal handling. For signals with handlers, we block all signals for the
106+
* duration of signal handler execution. We also do not set the SA_RESTART
107+
* flag; this should be safe given the tiny range of code in which the
108+
* postmaster ever unblocks signals.
109+
*
110+
* pqinitmask() must have been invoked previously.
111+
*
112+
* On Windows, this function is just an alias for pqsignal()
113+
* (and note that it's calling the code in src/backend/port/win32/signal.c,
114+
* not src/port/pqsignal.c). On that platform, the postmaster's signal
115+
* handlers still have to block signals for themselves.
116+
*/
117+
pqsigfunc
118+
pqsignal_pm(intsigno,pqsigfuncfunc)
119+
{
120+
#ifndefWIN32
121+
structsigactionact,
122+
oact;
123+
124+
act.sa_handler=func;
125+
if (func==SIG_IGN||func==SIG_DFL)
126+
{
127+
/* in these cases, act the same as pqsignal() */
128+
sigemptyset(&act.sa_mask);
129+
act.sa_flags=SA_RESTART;
130+
}
131+
else
132+
{
133+
act.sa_mask=BlockSig;
134+
act.sa_flags=0;
135+
}
136+
#ifdefSA_NOCLDSTOP
137+
if (signo==SIGCHLD)
138+
act.sa_flags |=SA_NOCLDSTOP;
139+
#endif
140+
if (sigaction(signo,&act,&oact)<0)
141+
returnSIG_ERR;
142+
returnoact.sa_handler;
143+
#else/* WIN32 */
144+
returnpqsignal(signo,func);
145+
#endif
146+
}

‎src/backend/postmaster/postmaster.c

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -632,14 +632,25 @@ PostmasterMain(int argc, char *argv[])
632632
/*
633633
* Set up signal handlers for the postmaster process.
634634
*
635-
* In the postmaster, we want to install non-ignored handlers *without*
636-
* SA_RESTART. This is because they'll be blocked at all times except
637-
* when ServerLoop is waiting for something to happen, and during that
638-
* window, we want signals to exit the select(2) wait so that ServerLoop
639-
* can respond if anything interesting happened. On some platforms,
640-
* signals marked SA_RESTART would not cause the select() wait to end.
641-
* Child processes will generally want SA_RESTART, but we expect them to
642-
* set up their own handlers before unblocking signals.
635+
* In the postmaster, we use pqsignal_pm() rather than pqsignal() (which
636+
* is used by all child processes and client processes). That has a
637+
* couple of special behaviors:
638+
*
639+
* 1. Except on Windows, we tell sigaction() to block all signals for the
640+
* duration of the signal handler. This is faster than our old approach
641+
* of blocking/unblocking explicitly in the signal handler, and it should
642+
* also prevent excessive stack consumption if signals arrive quickly.
643+
*
644+
* 2. We do not set the SA_RESTART flag. This is because signals will be
645+
* blocked at all times except when ServerLoop is waiting for something to
646+
* happen, and during that window, we want signals to exit the select(2)
647+
* wait so that ServerLoop can respond if anything interesting happened.
648+
* On some platforms, signals marked SA_RESTART would not cause the
649+
* select() wait to end.
650+
*
651+
* Child processes will generally want SA_RESTART, so pqsignal() sets that
652+
* flag. We expect children to set up their own handlers before
653+
* unblocking signals.
643654
*
644655
* CAUTION: when changing this list, check for side-effects on the signal
645656
* handling setup of child processes. See tcop/postgres.c,
@@ -651,23 +662,21 @@ PostmasterMain(int argc, char *argv[])
651662
pqinitmask();
652663
PG_SETMASK(&BlockSig);
653664

654-
pqsignal_no_restart(SIGHUP,SIGHUP_handler);/* reread config file and
655-
* have children do same */
656-
pqsignal_no_restart(SIGINT,pmdie);/* send SIGTERM and shut down */
657-
pqsignal_no_restart(SIGQUIT,pmdie);/* send SIGQUIT and die */
658-
pqsignal_no_restart(SIGTERM,pmdie);/* wait for children and shut down */
659-
pqsignal(SIGALRM,SIG_IGN);/* ignored */
660-
pqsignal(SIGPIPE,SIG_IGN);/* ignored */
661-
pqsignal_no_restart(SIGUSR1,sigusr1_handler);/* message from child
662-
* process */
663-
pqsignal_no_restart(SIGUSR2,dummy_handler);/* unused, reserve for
664-
* children */
665-
pqsignal_no_restart(SIGCHLD,reaper);/* handle child termination */
666-
pqsignal(SIGTTIN,SIG_IGN);/* ignored */
667-
pqsignal(SIGTTOU,SIG_IGN);/* ignored */
665+
pqsignal_pm(SIGHUP,SIGHUP_handler);/* reread config file and have
666+
* children do same */
667+
pqsignal_pm(SIGINT,pmdie);/* send SIGTERM and shut down */
668+
pqsignal_pm(SIGQUIT,pmdie);/* send SIGQUIT and die */
669+
pqsignal_pm(SIGTERM,pmdie);/* wait for children and shut down */
670+
pqsignal_pm(SIGALRM,SIG_IGN);/* ignored */
671+
pqsignal_pm(SIGPIPE,SIG_IGN);/* ignored */
672+
pqsignal_pm(SIGUSR1,sigusr1_handler);/* message from child process */
673+
pqsignal_pm(SIGUSR2,dummy_handler);/* unused, reserve for children */
674+
pqsignal_pm(SIGCHLD,reaper);/* handle child termination */
675+
pqsignal_pm(SIGTTIN,SIG_IGN);/* ignored */
676+
pqsignal_pm(SIGTTOU,SIG_IGN);/* ignored */
668677
/* ignore SIGXFSZ, so that ulimit violations work like disk full */
669678
#ifdefSIGXFSZ
670-
pqsignal(SIGXFSZ,SIG_IGN);/* ignored */
679+
pqsignal_pm(SIGXFSZ,SIG_IGN);/* ignored */
671680
#endif
672681

673682
/*
@@ -2594,7 +2603,13 @@ SIGHUP_handler(SIGNAL_ARGS)
25942603
{
25952604
intsave_errno=errno;
25962605

2606+
/*
2607+
* We rely on the signal mechanism to have blocked all signals ... except
2608+
* on Windows, which lacks sigaction(), so we have to do it manually.
2609+
*/
2610+
#ifdefWIN32
25972611
PG_SETMASK(&BlockSig);
2612+
#endif
25982613

25992614
if (Shutdown <=SmartShutdown)
26002615
{
@@ -2653,7 +2668,9 @@ SIGHUP_handler(SIGNAL_ARGS)
26532668
#endif
26542669
}
26552670

2671+
#ifdefWIN32
26562672
PG_SETMASK(&UnBlockSig);
2673+
#endif
26572674

26582675
errno=save_errno;
26592676
}
@@ -2667,7 +2684,13 @@ pmdie(SIGNAL_ARGS)
26672684
{
26682685
intsave_errno=errno;
26692686

2687+
/*
2688+
* We rely on the signal mechanism to have blocked all signals ... except
2689+
* on Windows, which lacks sigaction(), so we have to do it manually.
2690+
*/
2691+
#ifdefWIN32
26702692
PG_SETMASK(&BlockSig);
2693+
#endif
26712694

26722695
ereport(DEBUG2,
26732696
(errmsg_internal("postmaster received signal %d",
@@ -2796,7 +2819,9 @@ pmdie(SIGNAL_ARGS)
27962819
break;
27972820
}
27982821

2822+
#ifdefWIN32
27992823
PG_SETMASK(&UnBlockSig);
2824+
#endif
28002825

28012826
errno=save_errno;
28022827
}
@@ -2811,7 +2836,13 @@ reaper(SIGNAL_ARGS)
28112836
intpid;/* process id of dead child process */
28122837
intexitstatus;/* its exit status */
28132838

2839+
/*
2840+
* We rely on the signal mechanism to have blocked all signals ... except
2841+
* on Windows, which lacks sigaction(), so we have to do it manually.
2842+
*/
2843+
#ifdefWIN32
28142844
PG_SETMASK(&BlockSig);
2845+
#endif
28152846

28162847
ereport(DEBUG4,
28172848
(errmsg_internal("reaping dead processes")));
@@ -3114,7 +3145,9 @@ reaper(SIGNAL_ARGS)
31143145
PostmasterStateMachine();
31153146

31163147
/* Done with signal handler */
3148+
#ifdefWIN32
31173149
PG_SETMASK(&UnBlockSig);
3150+
#endif
31183151

31193152
errno=save_errno;
31203153
}
@@ -5048,7 +5081,13 @@ sigusr1_handler(SIGNAL_ARGS)
50485081
{
50495082
intsave_errno=errno;
50505083

5084+
/*
5085+
* We rely on the signal mechanism to have blocked all signals ... except
5086+
* on Windows, which lacks sigaction(), so we have to do it manually.
5087+
*/
5088+
#ifdefWIN32
50515089
PG_SETMASK(&BlockSig);
5090+
#endif
50525091

50535092
/* Process background worker state change. */
50545093
if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE))
@@ -5201,7 +5240,9 @@ sigusr1_handler(SIGNAL_ARGS)
52015240
signal_child(StartupPID,SIGUSR2);
52025241
}
52035242

5243+
#ifdefWIN32
52045244
PG_SETMASK(&UnBlockSig);
5245+
#endif
52055246

52065247
errno=save_errno;
52075248
}

‎src/include/libpq/pqsignal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,7 @@ extern sigset_t UnBlockSig,
3636

3737
externvoidpqinitmask(void);
3838

39+
/* pqsigfunc is declared in src/include/port.h */
40+
externpqsigfuncpqsignal_pm(intsigno,pqsigfuncfunc);
41+
3942
#endif/* PQSIGNAL_H */

‎src/include/port.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,6 @@ extern intpg_mkdir_p(char *path, int omode);
475475
/* port/pqsignal.c */
476476
typedefvoid (*pqsigfunc) (intsigno);
477477
externpqsigfuncpqsignal(intsigno,pqsigfuncfunc);
478-
#ifndefWIN32
479-
externpqsigfuncpqsignal_no_restart(intsigno,pqsigfuncfunc);
480-
#else
481-
#definepqsignal_no_restart(signo,func) pqsignal(signo, func)
482-
#endif
483478

484479
/* port/quotes.c */
485480
externchar*escape_single_quotes_ascii(constchar*src);

‎src/port/pqsignal.c

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,33 +58,4 @@ pqsignal(int signo, pqsigfunc func)
5858
#endif
5959
}
6060

61-
/*
62-
* Set up a signal handler, without SA_RESTART, for signal "signo"
63-
*
64-
* Returns the previous handler.
65-
*
66-
* On Windows, this would be identical to pqsignal(), so don't bother.
67-
*/
68-
#ifndefWIN32
69-
70-
pqsigfunc
71-
pqsignal_no_restart(intsigno,pqsigfuncfunc)
72-
{
73-
structsigactionact,
74-
oact;
75-
76-
act.sa_handler=func;
77-
sigemptyset(&act.sa_mask);
78-
act.sa_flags=0;
79-
#ifdefSA_NOCLDSTOP
80-
if (signo==SIGCHLD)
81-
act.sa_flags |=SA_NOCLDSTOP;
82-
#endif
83-
if (sigaction(signo,&act,&oact)<0)
84-
returnSIG_ERR;
85-
returnoact.sa_handler;
86-
}
87-
88-
#endif/* !WIN32 */
89-
9061
#endif/* !defined(WIN32) || defined(FRONTEND) */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp