PATCH: Keep one postmaster monitoring pipe per process
Hi,
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0]http://man.openbsd.org/OpenBSD-5.9/man2/select.2?manpath=OpenBSD-5.9 in the select/poll
implementation on some operating systems[1]At least OpenBSD and NetBSD are affected, FreeBSD rewrote their select implementation in 8.0.:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.
In our case the system had to wakeup ~3000 idle ssh processes
every time postgresql did call PostmasterIsAlive.
WalReceiver did run trigger with a rate of ~400 calls per second.
With the result that the system performs very badly,
being mostly busy scheduling idle processs.
Attached patch avoids the select contention by using a
separate pipe for each auxiliary and background process.
Since the postmaster has three different ways to create
new processes, the patch got a bit more complicated than
I anticipated :)
For auxiliary processes, pgstat, pgarch and the autovacuum launcher
get a preallocated pipe each. The pipes are held in:
postmaster_alive_fds_own[NUM_AUXPROCTYPES];
postmaster_alive_fds_watch[NUM_AUXPROCTYPES];
Just before we fork a new process we set postmaster_alive_fd
for each process type:
postmaster_alive_fd = postmaster_alive_fds_watch[type];
Since there can be multiple backend processes, BackendStarup()
allocates a pipe on-demand and keeps the reference in the Backend
structure. And is closed when the backend terminates.
The patch was developed and tested under OpenBSD using the REL9_4_STABLE
branch. I've merged it to current, compile tested and ran make check
on Ubuntu 14.04.
Marco
[0]: http://man.openbsd.org/OpenBSD-5.9/man2/select.2?manpath=OpenBSD-5.9
http://man.openbsd.org/OpenBSD-5.9/man2/select.2?manpath=OpenBSD-5.9
BUGS
[...]
"Internally to the kernel, select() and pselect() work poorly if multiple
processes wait on the same file descriptor. Given that, it is rather
surprising to see that many daemons are written that way."
[1]: At least OpenBSD and NetBSD are affected, FreeBSD rewrote their select implementation in 8.0.
At least OpenBSD and NetBSD are affected, FreeBSD rewrote
their select implementation in 8.0.
Attachments:
multi-pipe-monitor.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 1a92ca1..a3b4497 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -369,6 +369,13 @@ StartAutoVacLauncher(void)
{
pid_t AutoVacPID;
+#ifndef WIN32
+ /*
+ * Set the monitoring pipe for PostmasterIsAlive check
+ */
+ postmaster_alive_fd = postmaster_alive_fds_watch[AutoVacLauncherProcess];
+#endif
+
#ifdef EXEC_BACKEND
switch ((AutoVacPID = avlauncher_forkexec()))
#else
@@ -386,7 +393,7 @@ StartAutoVacLauncher(void)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, true);
AutoVacLauncherMain(0, NULL);
break;
@@ -1447,7 +1454,7 @@ StartAutoVacWorker(void)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
AutoVacWorkerMain(0, NULL);
break;
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 1aa6466..3ff3479 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -138,6 +138,13 @@ pgarch_start(void)
return 0;
last_pgarch_start_time = curtime;
+#ifndef WIN32
+ /*
+ * Set the monitoring pipe for PostmasterIsAlive check
+ */
+ postmaster_alive_fd = postmaster_alive_fds_watch[PgArchiverProcess];
+#endif
+
#ifdef EXEC_BACKEND
switch ((pgArchPid = pgarch_forkexec()))
#else
@@ -155,7 +162,7 @@ pgarch_start(void)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, true);
/* Drop our connection to postmaster's shared memory, as well */
dsm_detach_all();
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 8a2ce91..600fb14 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -676,6 +676,13 @@ pgstat_start(void)
return 0;
last_pgstat_start_time = curtime;
+#ifndef WIN32
+ /*
+ * Set the monitoring pipe for PostmasterIsAlive check
+ */
+ postmaster_alive_fd = postmaster_alive_fds_watch[PgStatProcess];
+#endif
+
/*
* Okay, fork off the collector.
*/
@@ -696,7 +703,7 @@ pgstat_start(void)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, true);
/* Drop our connection to postmaster's shared memory, as well */
dsm_detach_all();
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index eaf3f61..6eb8f48 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -176,6 +176,7 @@ typedef struct bkend
bool dead_end; /* is it going to send an error and quit? */
bool bgworker_notify; /* gets bgworker start/stop notifications */
dlist_node elem; /* list link in BackendList */
+ int postmaster_alive_fd_own;
} Backend;
static dlist_head BackendList = DLIST_STATIC_INIT(BackendList);
@@ -416,6 +417,7 @@ static void maybe_start_bgworker(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
static pid_t StartChildProcess(AuxProcType type);
static void StartAutovacuumWorker(void);
+static void CreatePostmasterDeathWatchPipe(int *ownfd, int *watchfd);
static void InitPostmasterDeathWatchHandle(void);
/*
@@ -507,7 +509,7 @@ typedef struct
HANDLE initial_signal_pipe;
HANDLE syslogPipe[2];
#else
- int postmaster_alive_fds[2];
+ int postmaster_alive_fd;
int syslogPipe[2];
#endif
char my_exec_path[MAXPGPATH];
@@ -542,10 +544,13 @@ static void ShmemBackendArrayRemove(Backend *bn);
#ifndef WIN32
/*
- * File descriptors for pipe used to monitor if postmaster is alive.
- * First is POSTMASTER_FD_WATCH, second is POSTMASTER_FD_OWN.
+ * File descriptors for pipes used to monitor if postmaster is alive.
+ * Every process gets it's own pipe.
+ * Contains the postmaster end of each pipe.
*/
-int postmaster_alive_fds[2] = {-1, -1};
+int postmaster_alive_fds_own[NUM_AUXPROCTYPES];
+int postmaster_alive_fds_watch[NUM_AUXPROCTYPES];
+int postmaster_alive_fd = -1; /* set per child */
#else
/* Process handle of postmaster used for the same purpose on Windows */
HANDLE PostmasterHandle;
@@ -2384,11 +2389,13 @@ ConnFree(Port *conn)
* that are not needed by that child process. The postmaster still has
* them open, of course.
*
+ * monitor_pm is set for childs that run the PostmasterIsAlive check
+ *
* Note: we pass am_syslogger as a boolean because we don't want to set
* the global variable yet when this is called.
*/
void
-ClosePostmasterPorts(bool am_syslogger)
+ClosePostmasterPorts(bool am_syslogger, bool monitor_pm)
{
int i;
@@ -2398,12 +2405,32 @@ ClosePostmasterPorts(bool am_syslogger)
* Close the write end of postmaster death watch pipe. It's important to
* do this as early as possible, so that if postmaster dies, others won't
* think that it's still running because we're holding the pipe open.
+ *
+ * For child processes that don't monitor the postmaster, all the
+ * monitoring pipes are closed.
*/
- if (close(postmaster_alive_fds[POSTMASTER_FD_OWN]))
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg_internal("could not close postmaster death monitoring pipe in child process: %m")));
- postmaster_alive_fds[POSTMASTER_FD_OWN] = -1;
+ for (i = 0; i < NUM_AUXPROCTYPES; i++) {
+ if (monitor_pm)
+ {
+ if (postmaster_alive_fds_watch[i] != postmaster_alive_fd)
+ {
+ close(postmaster_alive_fds_watch[i]);
+ postmaster_alive_fds_watch[i] = -1;
+ }
+ if (close(postmaster_alive_fds_own[i]))
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg_internal("could not close postmaster death monitoring pipe in child process: %m")));
+ postmaster_alive_fds_own[i] = -1;
+ }
+ else
+ {
+ close(postmaster_alive_fds_own[i]);
+ postmaster_alive_fds_own[i] = -1;
+ close(postmaster_alive_fds_watch[i]);
+ postmaster_alive_fds_watch[i] = -1;
+ }
+ }
#endif
/* Close the listen sockets */
@@ -3175,6 +3202,7 @@ CleanupBackend(int pid,
BackgroundWorkerStopNotifications(bp->pid);
}
dlist_delete(iter.cur);
+ close(bp->postmaster_alive_fd_own);
free(bp);
break;
}
@@ -3278,6 +3306,7 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
#endif
}
dlist_delete(iter.cur);
+ close(bp->postmaster_alive_fd_own);
free(bp);
/* Keep looping so we can signal remaining backends */
}
@@ -3913,19 +3942,36 @@ BackendStartup(Port *port)
/* Hasn't asked to be notified about any bgworkers yet */
bn->bgworker_notify = false;
+#ifndef WIN32
+ CreatePostmasterDeathWatchPipe(
+ &bn->postmaster_alive_fd_own,
+ &postmaster_alive_fd);
+#else
+ bn->postmaster_alive_fd_own = -1;
+#endif
+
#ifdef EXEC_BACKEND
pid = backend_forkexec(port);
#else /* !EXEC_BACKEND */
pid = fork_process();
if (pid == 0) /* child */
{
- free(bn);
+ dlist_iter iter;
/* Detangle from postmaster */
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
+ close(bn->postmaster_alive_fd_own);
+
+ dlist_foreach(iter, &BackendList)
+ {
+ Backend *bp = dlist_container(Backend, elem, iter.cur);
+ close(bp->postmaster_alive_fd_own);
+ }
+
+ free(bn);
/* Perform additional initialization and collect startup packet */
BackendInitialize(port);
@@ -3942,6 +3988,8 @@ BackendStartup(Port *port)
if (!bn->dead_end)
(void) ReleasePostmasterChildSlot(bn->child_slot);
+ close(postmaster_alive_fd);
+ close(bn->postmaster_alive_fd_own);
free(bn);
errno = save_errno;
ereport(LOG,
@@ -3959,6 +4007,8 @@ BackendStartup(Port *port)
* Everything's been successful, it's safe to add this backend to our list
* of backends.
*/
+ close(postmaster_alive_fd);
+ postmaster_alive_fd = -1;
bn->pid = pid;
bn->bkend_type = BACKEND_TYPE_NORMAL; /* Can change later to WALSND */
dlist_push_head(&BackendList, &bn->elem);
@@ -4701,7 +4751,7 @@ SubPostmasterMain(int argc, char *argv[])
Assert(argc == 3); /* shouldn't be any more args */
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/*
* Need to reinitialize the SSL library in the backend, since the
@@ -4752,7 +4802,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkboot") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Restore basic shared memory pointers */
InitShmemAccess(UsedShmemSegAddr);
@@ -4768,7 +4818,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkavlauncher") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Restore basic shared memory pointers */
InitShmemAccess(UsedShmemSegAddr);
@@ -4784,7 +4834,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkavworker") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Restore basic shared memory pointers */
InitShmemAccess(UsedShmemSegAddr);
@@ -4805,7 +4855,7 @@ SubPostmasterMain(int argc, char *argv[])
IsBackgroundWorker = true;
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Restore basic shared memory pointers */
InitShmemAccess(UsedShmemSegAddr);
@@ -4825,7 +4875,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkarch") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Do not want to attach to shared memory */
@@ -4834,7 +4884,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forkcol") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/* Do not want to attach to shared memory */
@@ -4843,7 +4893,7 @@ SubPostmasterMain(int argc, char *argv[])
if (strcmp(argv[1], "--forklog") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(true);
+ ClosePostmasterPorts(true, false);
/* Do not want to attach to shared memory */
@@ -5207,6 +5257,8 @@ StartChildProcess(AuxProcType type)
av[ac] = NULL;
Assert(ac < lengthof(av));
+ postmaster_alive_fd = postmaster_alive_fds_watch[type];
+
#ifdef EXEC_BACKEND
pid = postmaster_forkexec(ac, av);
#else /* !EXEC_BACKEND */
@@ -5217,7 +5269,7 @@ StartChildProcess(AuxProcType type)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, true);
/* Release postmaster's working memory context */
MemoryContextSwitchTo(TopMemoryContext);
@@ -5275,6 +5327,7 @@ StartChildProcess(AuxProcType type)
/*
* in parent, successful fork
*/
+ postmaster_alive_fd = -1;
return pid;
}
@@ -5523,7 +5576,7 @@ do_start_bgworker(RegisteredBgWorker *rw)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts(false, false);
/*
* Before blowing away PostmasterContext, save this bgworker's
@@ -5841,8 +5894,7 @@ save_backend_variables(BackendParameters *param, Port *port,
childProcess))
return false;
#else
- memcpy(¶m->postmaster_alive_fds, &postmaster_alive_fds,
- sizeof(postmaster_alive_fds));
+ param->postmaster_alive_fd = postmaster_alive_fd;
#endif
memcpy(¶m->syslogPipe, &syslogPipe, sizeof(syslogPipe));
@@ -6070,8 +6122,8 @@ restore_backend_variables(BackendParameters *param, Port *port)
PostmasterHandle = param->PostmasterHandle;
pgwin32_initial_signal_pipe = param->initial_signal_pipe;
#else
- memcpy(&postmaster_alive_fds, ¶m->postmaster_alive_fds,
- sizeof(postmaster_alive_fds));
+ memcpy(&postmaster_alive_fds_watch, ¶m->postmaster_alive_fds_watch,
+ sizeof(postmaster_alive_fds_watch));
#endif
memcpy(&syslogPipe, ¶m->syslogPipe, sizeof(syslogPipe));
@@ -6197,8 +6249,29 @@ pgwin32_deadchild_callback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
}
#endif /* WIN32 */
+static void
+CreatePostmasterDeathWatchPipe(int *ownfd, int *watchfd)
+{
+ int tmp_pipe[2];
+
+ if (pipe(tmp_pipe))
+ ereport(FATAL,
+ (errcode_for_file_access(),
+ errmsg_internal("could not create pipe to monitor postmaster death: %m")));
+ /*
+ * Set O_NONBLOCK to allow testing for the fd's presence with a read()
+ * call.
+ */
+ if (fcntl(tmp_pipe[POSTMASTER_FD_WATCH], F_SETFL, O_NONBLOCK))
+ ereport(FATAL,
+ (errcode_for_socket_access(),
+ errmsg_internal("could not set postmaster death monitoring pipe to nonblocking mode: %m")));
+ *ownfd = tmp_pipe[POSTMASTER_FD_OWN];
+ *watchfd = tmp_pipe[POSTMASTER_FD_WATCH];
+}
+
/*
- * Initialize one and only handle for monitoring postmaster death.
+ * Initialize one per process handle for monitoring postmaster death.
*
* Called once in the postmaster, so that child processes can subsequently
* monitor if their parent is dead.
@@ -6208,9 +6281,12 @@ InitPostmasterDeathWatchHandle(void)
{
#ifndef WIN32
+ int i;
+
/*
- * Create a pipe. Postmaster holds the write end of the pipe open
- * (POSTMASTER_FD_OWN), and children hold the read end. Children can pass
+ * Create a pipe for each Auxiliary Proc.
+ * Postmaster holds the write end of the pipe open
+ * (postmaster_alive_fds_own[]), and children hold the read end. Children can pass
* the read file descriptor to select() to wake up in case postmaster
* dies, or check for postmaster death with a (read() == 0). Children must
* close the write end as soon as possible after forking, because EOF
@@ -6218,19 +6294,12 @@ InitPostmasterDeathWatchHandle(void)
* write fd. That is taken care of in ClosePostmasterPorts().
*/
Assert(MyProcPid == PostmasterPid);
- if (pipe(postmaster_alive_fds))
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg_internal("could not create pipe to monitor postmaster death: %m")));
+ for (i = 0; i < NUM_AUXPROCTYPES; i++) {
+ CreatePostmasterDeathWatchPipe(
+ &postmaster_alive_fds_own[i],
+ &postmaster_alive_fds_watch[i]);
+ }
- /*
- * Set O_NONBLOCK to allow testing for the fd's presence with a read()
- * call.
- */
- if (fcntl(postmaster_alive_fds[POSTMASTER_FD_WATCH], F_SETFL, O_NONBLOCK))
- ereport(FATAL,
- (errcode_for_socket_access(),
- errmsg_internal("could not set postmaster death monitoring pipe to nonblocking mode: %m")));
#else
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index e7e488a..3e3e81e 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -590,7 +590,7 @@ SysLogger_Start(void)
InitPostmasterChild();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(true);
+ ClosePostmasterPorts(true, false);
/* Drop our connection to postmaster's shared memory, as well */
dsm_detach_all();
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 9def8a1..f5198df 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -652,7 +652,7 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
else if (events == WL_POSTMASTER_DEATH)
{
#ifndef WIN32
- event->fd = postmaster_alive_fds[POSTMASTER_FD_WATCH];
+ event->fd = postmaster_alive_fd;
#endif
}
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index 7ae622c..c0ef6e5 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -275,7 +275,7 @@ PostmasterIsAlive(void)
char c;
ssize_t rc;
- rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
+ rc = read(postmaster_alive_fd, &c, 1);
if (rc < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 78545da..6cc0364 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -392,6 +392,14 @@ typedef enum
CheckpointerProcess,
WalWriterProcess,
WalReceiverProcess,
+ /*
+ * The types below are not auxiliary processes.
+ * We abuse the identifiers as a reference for
+ * the per-process postmaster monitoring pipe
+ */
+ PgArchiverProcess,
+ AutoVacLauncherProcess,
+ PgStatProcess,
NUM_AUXPROCTYPES /* Must be last! */
} AuxProcType;
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index b2d7776..ceeccb3 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -13,6 +13,8 @@
#ifndef _POSTMASTER_H
#define _POSTMASTER_H
+#include "miscadmin.h"
+
/* GUC options */
extern bool EnableSSL;
extern int ReservedBackends;
@@ -33,7 +35,8 @@ extern bool restart_after_crash;
#ifdef WIN32
extern HANDLE PostmasterHandle;
#else
-extern int postmaster_alive_fds[2];
+extern int postmaster_alive_fds_watch[NUM_AUXPROCTYPES];
+extern int postmaster_alive_fd;
/*
* Constants that represent which of postmaster_alive_fds is held by
@@ -47,7 +50,7 @@ extern int postmaster_alive_fds[2];
extern const char *progname;
extern void PostmasterMain(int argc, char *argv[]) pg_attribute_noreturn();
-extern void ClosePostmasterPorts(bool am_syslogger);
+extern void ClosePostmasterPorts(bool am_syslogger, bool monitor_pm);
extern int MaxLivePostmasterChildren(void);
Hi,
On 2016-09-15 15:57:55 +0200, Marco Pfatschbacher wrote:
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0] in the select/poll
implementation on some operating systems[1]:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.
Yikes, that's a pretty absurd implementation.
Does openbsd's kqueue implementation have the same issue? There's
http://archives.postgresql.org/message-id/CAEepm%3D37oF84-iXDTQ9MrGjENwVGds%2B5zTr38ca73kWR7ez_tA%40mail.gmail.com
Attached patch avoids the select contention by using a
separate pipe for each auxiliary and background process.
I'm quite unenthusiastic about forcing that many additional file
descriptors onto the postmaster...
I'm not quite sure I understand why this an issue here - there shouldn't
ever be events on this fd, so why is the kernel waking up all processes?
It'd kinda makes sense it'd wake up all processes if there's one
waiting, but ... ?
BUGS
[...]
"Internally to the kernel, select() and pselect() work poorly if multiple
processes wait on the same file descriptor. Given that, it is rather
surprising to see that many daemons are written that way."
Gee. Maybe it's more surprising that that issue isn't being addressed?
Regards,
Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Sep 16, 2016 at 1:57 AM, Marco Pfatschbacher
<Marco_Pfatschbacher@genua.de> wrote:
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0] in the select/poll
implementation on some operating systems[1]:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.[...]
BUGS
[...]
"Internally to the kernel, select() and pselect() work poorly if multiple
processes wait on the same file descriptor. Given that, it is rather
surprising to see that many daemons are written that way."[1]
At least OpenBSD and NetBSD are affected, FreeBSD rewrote
their select implementation in 8.0.
Very interesting. Perhaps that is why NetBSD shows a speedup with the
kqueue patch[1]/messages/by-id/CAEepm=2i78TOJeV4O0-0meiihiRfVQ29ur7=MBHxsUKaPSWeAg@mail.gmail.com but FreeBSD doesn't. I guess that if I could get the
kqueue patch to perform better on large FreeBSD systems, it would also
be a solution to this problem.
[1]: /messages/by-id/CAEepm=2i78TOJeV4O0-0meiihiRfVQ29ur7=MBHxsUKaPSWeAg@mail.gmail.com
--
Thomas Munro
http://www.enterprisedb.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Marco Pfatschbacher <Marco_Pfatschbacher@genua.de> writes:
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0] in the select/poll
implementation on some operating systems[1]:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.
That seems like a rather bad kernel bug.
In our case the system had to wakeup ~3000 idle ssh processes
every time postgresql did call PostmasterIsAlive.
Uh, these are processes not even connected to the pipe in question?
That's *really* a kernel bug.
Attached patch avoids the select contention by using a
separate pipe for each auxiliary and background process.
I think this would likely move the performance problems somewhere else.
In particular, it would mean that every postmaster child would inherit
pipes leading to all the older children. We could close 'em again
I guess, but we have previously found that having to do things that
way is a rather serious performance drag --- see the problems we had
with POSIX named semaphores, here for instance:
/messages/by-id/3830CBEB-F8CE-4EBC-BE16-A415E78A4CBC@apple.com
I really don't want the postmaster to be holding any per-child kernel
resources.
It'd certainly be nice if we could find another solution besides
the pipe-based one, but I don't think "more pipes" is the answer.
There was some discussion of using Linux's prctl(PR_SET_PDEATHSIG)
when available; do the BSDen have anything like that?
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Thomas Munro <thomas.munro@enterprisedb.com> writes:
Very interesting. Perhaps that is why NetBSD shows a speedup with the
kqueue patch[1] but FreeBSD doesn't. I guess that if I could get the
kqueue patch to perform better on large FreeBSD systems, it would also
be a solution to this problem.
I just noticed that kqueue appears to offer a solution to this problem,
ie one of the things you can wait for is exit of another process (named
by PID, looks like). If that's portable to all kqueue platforms, then
integrating a substitute for the postmaster death pipe might push that
patch over the hump to being a net win.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Sep 15, 2016 at 04:24:07PM -0400, Tom Lane wrote:
Marco Pfatschbacher <Marco_Pfatschbacher@genua.de> writes:
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0] in the select/poll
implementation on some operating systems[1]:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.That seems like a rather bad kernel bug.
It's a limitation that has been there since at least BSD4.4.
But yeah, I wished things were better.
In our case the system had to wakeup ~3000 idle ssh processes
every time postgresql did call PostmasterIsAlive.Uh, these are processes not even connected to the pipe in question?
That's *really* a kernel bug.
The kernel does not know if they were selecting on that pipe,
because the only slot to keep that mapping has been already taken.
It's not that bad of a performance hit, If the system doesn't
many processes.
Attached patch avoids the select contention by using a
separate pipe for each auxiliary and background process.I think this would likely move the performance problems somewhere else.
In particular, it would mean that every postmaster child would inherit
pipes leading to all the older children.
I kept them at a minimum. (See ClosePostmasterPorts)
We could close 'em again
I guess, but we have previously found that having to do things that
way is a rather serious performance drag --- see the problems we had
I think closing a few files doesn't hurt too much, but I see your point.
with POSIX named semaphores, here for instance:
/messages/by-id/3830CBEB-F8CE-4EBC-BE16-A415E78A4CBC@apple.com
I really don't want the postmaster to be holding any per-child kernel
resources.It'd certainly be nice if we could find another solution besides
the pipe-based one, but I don't think "more pipes" is the answer.
There was some discussion of using Linux's prctl(PR_SET_PDEATHSIG)
when available; do the BSDen have anything like that?
Not that I know of.
But since the WalReceiver process seemed to be the one calling
PostmasterIsAlive way more often than the rest, maybe we could limit
the performance hit by not calling it on every received wal chunk?
Cheers,
Marco
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Sep 15, 2016 at 04:40:00PM -0400, Tom Lane wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
Very interesting. Perhaps that is why NetBSD shows a speedup with the
kqueue patch[1] but FreeBSD doesn't. I guess that if I could get the
kqueue patch to perform better on large FreeBSD systems, it would also
be a solution to this problem.I just noticed that kqueue appears to offer a solution to this problem,
ie one of the things you can wait for is exit of another process (named
by PID, looks like). If that's portable to all kqueue platforms, then
integrating a substitute for the postmaster death pipe might push that
patch over the hump to being a net win.
That sounds plausible.
I could give this a try after I get back from my vacation :)
Marco
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Sep 15, 2016 at 12:26:16PM -0700, Andres Freund wrote:
Hi,
On 2016-09-15 15:57:55 +0200, Marco Pfatschbacher wrote:
the current implementation of PostmasterIsAlive() uses a pipe to
monitor the existence of the postmaster process.
One end of the pipe is held open in the postmaster, while the other end is
inherited to all the auxiliary and background processes when they fork.
This leads to multiple processes calling select(2), poll(2) and read(2)
on the same end of the pipe.
While this is technically perfectly ok, it has the unfortunate side
effect that it triggers an inefficient behaviour[0] in the select/poll
implementation on some operating systems[1]:
The kernel can only keep track of one pid per select address and
thus has no other choice than to wakeup(9) every process that
is waiting on select/poll.Yikes, that's a pretty absurd implementation.
Not when you take into account that it's been written over 20 years ago ;)
Does openbsd's kqueue implementation have the same issue? There's
http://archives.postgresql.org/message-id/CAEepm%3D37oF84-iXDTQ9MrGjENwVGds%2B5zTr38ca73kWR7ez_tA%40mail.gmail.com
Looks ok, but your milage may vary. I've seen strange subtle bugs
using kqeue..
struct kevent {
__uintptr_t ident; /* identifier for this event */
short filter; /* filter for event */
u_short flags;
u_int fflags;
quad_t data;
void *udata; /* opaque user data identifier */
};
Attached patch avoids the select contention by using a
separate pipe for each auxiliary and background process.I'm quite unenthusiastic about forcing that many additional file
descriptors onto the postmaster...
In our use case it's about 30.
I'm not quite sure I understand why this an issue here - there shouldn't
ever be events on this fd, so why is the kernel waking up all processes?
It'd kinda makes sense it'd wake up all processes if there's one
waiting, but ... ?
Every read is an event, and that's what PostmasterIsAlive does.
Marco
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2016-09-16 09:55:48 +0200, Marco Pfatschbacher wrote:
On Thu, Sep 15, 2016 at 12:26:16PM -0700, Andres Freund wrote:
Yikes, that's a pretty absurd implementation.
Not when you take into account that it's been written over 20 years ago ;)
Well, that doesn't mean it can't be fixed ;)
I'm not quite sure I understand why this an issue here - there shouldn't
ever be events on this fd, so why is the kernel waking up all processes?
It'd kinda makes sense it'd wake up all processes if there's one
waiting, but ... ?Every read is an event, and that's what PostmasterIsAlive does.
But in most places we only do a PostmasterIsAlive if WaitLatch returns
WL_POSTMASTER_DEATH. The only walreceiver related place that doesn't is
WalRcvWaitForStartPosition(). If that's indeed the cause of your issues
this quite possibly could be fixed by doing the
if (!PostmasterIsAlive())
exit(1);
check not unconditionally, but only after the WaitLatch at the end of
the loop, and only if WL_POSTMASTER_DEATH is returned by WaitLatch()?
That'll be a minor behaviour change for the WALRCV_RESTARTING, but that
seems fine, we'll just loop once more outside (after a quick glance at
least).
Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Sep 16, 2016 at 2:23 PM, Andres Freund <andres@anarazel.de> wrote:
Every read is an event, and that's what PostmasterIsAlive does.
But in most places we only do a PostmasterIsAlive if WaitLatch returns
WL_POSTMASTER_DEATH. The only walreceiver related place that doesn't is
WalRcvWaitForStartPosition(). If that's indeed the cause of your issues
this quite possibly could be fixed by doing the
if (!PostmasterIsAlive())
exit(1);
check not unconditionally, but only after the WaitLatch at the end of
the loop, and only if WL_POSTMASTER_DEATH is returned by WaitLatch()?
That'll be a minor behaviour change for the WALRCV_RESTARTING, but that
seems fine, we'll just loop once more outside (after a quick glance at
least).
At least some of the latch implementations already check
PostmasterIsAlive() internally to avoid returning spurious events; and
secure_read() at least assumes that the WL_POSTMASTER_DEATH return is
reliable and doesn't need a double-check.
So we can probably just remove the check altogether and instead bail
out if it returns WL_POSTMASTER_DEATH. That probably saves a system
call per loop iteration even on platforms where the kernel doesn't
exhibit any surprising behavior.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Sat, Sep 17, 2016 at 6:23 AM, Andres Freund <andres@anarazel.de> wrote:
On 2016-09-16 09:55:48 +0200, Marco Pfatschbacher wrote:
On Thu, Sep 15, 2016 at 12:26:16PM -0700, Andres Freund wrote:
Yikes, that's a pretty absurd implementation.
Not when you take into account that it's been written over 20 years ago ;)
Well, that doesn't mean it can't be fixed ;)
I'm not quite sure I understand why this an issue here - there shouldn't
ever be events on this fd, so why is the kernel waking up all processes?
It'd kinda makes sense it'd wake up all processes if there's one
waiting, but ... ?Every read is an event, and that's what PostmasterIsAlive does.
But in most places we only do a PostmasterIsAlive if WaitLatch returns
WL_POSTMASTER_DEATH. The only walreceiver related place that doesn't is
WalRcvWaitForStartPosition(). If that's indeed the cause of your issues
this quite possibly could be fixed by doing the
if (!PostmasterIsAlive())
exit(1);
check not unconditionally, but only after the WaitLatch at the end of
the loop, and only if WL_POSTMASTER_DEATH is returned by WaitLatch()?
That'll be a minor behaviour change for the WALRCV_RESTARTING, but that
seems fine, we'll just loop once more outside (after a quick glance at
least).
Yeah, I wondered why that was different than the pattern established
elsewhere when I was hacking on replication code. There are actually
several places where we call PostmasterIsAlive() unconditionally in a
loop that waits for WL_POSTMASTER_DEATH but ignores the return code:
in pgarch.c, syncrep.c, walsender.c and walreceiver.c. Should we just
change them all to check the return code and exit/break/ereport/etc as
appropriate? That would match the code from autovacuum.c,
checkpointer.c, pgstat.c, be-secure.c and bgworker.c. Something like
the attached.
The code in basebackup.c also waits for WL_POSTMASTER_DEATH but
doesn't check for it in the return value *or* call
PostmasterIsAlive(). I'm not sure what to make of that. I didn't
test it but it looks like maybe it would continue running after
postmaster death but not honour the throttling rate limit because
WaitLatch would keep returning immediately.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
check-return-code-for-postmaster-death.patchapplication/octet-stream; name=check-return-code-for-postmaster-death.patchDownload
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 1aa6466..00d0808 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
timeout * 1000L);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index b442d06..6e10f6e 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -189,6 +189,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -242,23 +244,23 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
}
/*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1);
+
+ /*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 413ee3a..6c5714a 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -650,14 +650,9 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
WakeupRecovery();
for (;;)
{
- ResetLatch(&walrcv->latch);
+ int rc;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
+ ResetLatch(&walrcv->latch);
ProcessWalRcvInterrupts();
@@ -685,7 +680,10 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
+ rc = WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
if (update_process_title)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index c7743da..751d75d 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1096,17 +1096,11 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
for (;;)
{
+ int rc;
int wakeEvents;
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1145,8 +1139,11 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -1180,16 +1177,10 @@ WalSndWaitForWal(XLogRecPtr loc)
for (;;)
{
+ int rc;
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1271,8 +1262,11 @@ WalSndWaitForWal(XLogRecPtr loc)
wakeEvents |= WL_SOCKET_WRITEABLE;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -1817,13 +1811,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1911,6 +1898,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
*/
if ((WalSndCaughtUp && !streamingDoneSending) || pq_is_send_pending())
{
+ int rc;
long sleeptime;
int wakeEvents;
@@ -1923,8 +1911,11 @@ WalSndLoop(WalSndSendDataCallback send_data)
wakeEvents |= WL_SOCKET_WRITEABLE;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
}
return;
On 2016-09-20 11:07:03 +1200, Thomas Munro wrote:
Yeah, I wondered why that was different than the pattern established
elsewhere when I was hacking on replication code. There are actually
several places where we call PostmasterIsAlive() unconditionally in a
loop that waits for WL_POSTMASTER_DEATH but ignores the return code:
Note that just changing this implies a behavioural change in at least
some of those: If the loop is busy with work, the WaitLatch might never
be reached. I think that might be ok in most of those, but it does
require examination.
- Andres
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Thu, Sep 15, 2016 at 04:40:00PM -0400, Tom Lane wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
Very interesting. Perhaps that is why NetBSD shows a speedup with the
kqueue patch[1] but FreeBSD doesn't. I guess that if I could get the
kqueue patch to perform better on large FreeBSD systems, it would also
be a solution to this problem.I just noticed that kqueue appears to offer a solution to this problem,
ie one of the things you can wait for is exit of another process (named
by PID, looks like). If that's portable to all kqueue platforms, then
integrating a substitute for the postmaster death pipe might push that
patch over the hump to being a net win.regards, tom lane
Hi,
sorry for the long silence.
I forgot about this after being on vacation.
kqueue does indeed support EVFILT_PROC like you said.
But using this effectively, would need a separate monitoring process,
because we cannot use poll(2) and kevent(2) together within the same loop.
But how about this:
We just use getppid to see whether the process id of our parent
has changed to 1 (init).
Just like calling read on the pipe, that's just one systemcall.
I did not bother to weed the postmaster_alive_fds yet, but
this change works fine for me.
Regards,
Marco
diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c
index 85db6b21f8..a0596c61fd 100644
--- a/src/backend/storage/ipc/pmsignal.c
+++ b/src/backend/storage/ipc/pmsignal.c
@@ -272,21 +272,16 @@ bool
PostmasterIsAlive(void)
{
#ifndef WIN32
- char c;
- ssize_t rc;
+ pid_t ppid;
- rc = read(postmaster_alive_fds[POSTMASTER_FD_WATCH], &c, 1);
- if (rc < 0)
+ ppid = getppid();
+ if (ppid == 1)
{
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- return true;
- else
- elog(FATAL, "read on postmaster death monitoring pipe failed: %m");
+ elog(FATAL, "postmaster died: our ppid changed to init");
+ return false;
}
- else if (rc > 0)
- elog(FATAL, "unexpected data in postmaster death monitoring pipe");
- return false;
+ return true;
#else /* WIN32 */
return (WaitForSingleObject(PostmasterHandle, 0) == WAIT_TIMEOUT);
#endif /* WIN32 */
On Tue, Dec 5, 2017 at 5:55 AM, Marco Pfatschbacher
<Marco_Pfatschbacher@genua.de> wrote:
On Thu, Sep 15, 2016 at 04:40:00PM -0400, Tom Lane wrote:
I just noticed that kqueue appears to offer a solution to this problem,
ie one of the things you can wait for is exit of another process (named
by PID, looks like). If that's portable to all kqueue platforms, then
integrating a substitute for the postmaster death pipe might push that
patch over the hump to being a net win.kqueue does indeed support EVFILT_PROC like you said.
But using this effectively, would need a separate monitoring process,
because we cannot use poll(2) and kevent(2) together within the same loop.
FWIW the kqueue patch I posted uses EVFILT_PROC as Tom suggested and
it works fine according to my testing (FreeBSD +macOS). With that
patch, there is no poll, just kqueue everywhere.
But how about this:
We just use getppid to see whether the process id of our parent
has changed to 1 (init).
Just like calling read on the pipe, that's just one systemcall.
I'm still not sure why we have to make any system calls at all. Do we
not trust WaitLatch() to tell us about WL_POSTMASTER_DEATH reliably,
or is it that we don't trust it to tell us about that event when there
are other events happening due to priorities, or...?
--
Thomas Munro
http://www.enterprisedb.com
On Tue, Sep 20, 2016 at 11:26 AM, Andres Freund <andres@anarazel.de> wrote:
On 2016-09-20 11:07:03 +1200, Thomas Munro wrote:
Yeah, I wondered why that was different than the pattern established
elsewhere when I was hacking on replication code. There are actually
several places where we call PostmasterIsAlive() unconditionally in a
loop that waits for WL_POSTMASTER_DEATH but ignores the return code:Note that just changing this implies a behavioural change in at least
some of those: If the loop is busy with work, the WaitLatch might never
be reached. I think that might be ok in most of those, but it does
require examination.
Rebased, but I don't actually like this patch any more. Over in
another thread[1]/messages/by-id/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com I proposed that we should just make exit(1) the
default behaviour built into latch.c for those cases that don't want
to do something special (eg SyncRepWaitForLSN()), so we don't finish
up duplicating the ugly exit(1) code everywhere (or worse, forgetting
to). Tom Lane seemed to think that was an idea worth pursuing.
I think what we need for PG12 is a patch that does that, and also
introduces a reused WaitEventSet object in several of these places.
Then eg SyncRepWaitForLSN() won't be interacting with contended kernel
objects every time (assuming an implementation like epoll or
eventually kqueue, completion ports etc is available).
Then if pgarch_ArchiverCopyLoop() and HandleStartupProcInterrupts()
(ie loops without waiting) adopt a prctl(PR_SET_PDEATHSIG)-based
approach where available as suggested by Andres[2]/messages/by-id/7261eb39-0369-f2f4-1bb5-62f3b6083b5e@iki.fi or fall back to
polling a reusable WaitEventSet (timeout = 0), then there'd be no more
calls to PostmasterIsAlive() outside latch.c.
[1]: /messages/by-id/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
[2]: /messages/by-id/7261eb39-0369-f2f4-1bb5-62f3b6083b5e@iki.fi
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Replace-PostmasterIsAlive-calls-with-WL_POSTMASTER_D.patchapplication/octet-stream; name=0001-Replace-PostmasterIsAlive-calls-with-WL_POSTMASTER_D.patchDownload
From ae87ca271dc8bd27a0d74ba3afecad2c54e86a90 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Replace PostmasterIsAlive() calls with WL_POSTMASTER_DEATH
checks.
In several places we had a loop with a WaitEventSet, but we also made an
explicit PostmasterIsAlive() call. That caused contention in the kernel of
some operating systems, and was mostly redundant because we already receive
notification from the WaitEventSet system when the postmaster dies.
---
src/backend/postmaster/pgarch.c | 4 ++-
src/backend/replication/syncrep.c | 18 ++++++++------
src/backend/replication/walreceiver.c | 16 ++++++------
src/backend/replication/walsender.c | 47 ++++++++++++++---------------------
4 files changed, 39 insertions(+), 46 deletions(-)
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b9dab322d6b..b097b724fce 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -681,14 +681,9 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
WakeupRecovery();
for (;;)
{
- ResetLatch(walrcv->latch);
+ int rc;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
+ ResetLatch(walrcv->latch);
ProcessWalRcvInterrupts();
@@ -716,8 +711,11 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
- WAIT_EVENT_WAL_RECEIVER_WAIT_START);
+ rc = WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WAIT_EVENT_WAL_RECEIVER_WAIT_START);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
if (update_process_title)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 642e859439f..51aa26627a1 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1186,6 +1186,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
/* If we have pending write here, go to slow path */
for (;;)
{
+ int rc;
int wakeEvents;
long sleeptime;
@@ -1209,15 +1210,11 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_WRITE_DATA);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
exit(1);
/* Clear any already-pending wakeups */
@@ -1297,16 +1294,10 @@ WalSndWaitForWal(XLogRecPtr loc)
for (;;)
{
+ int rc;
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1406,9 +1397,12 @@ WalSndWaitForWal(XLogRecPtr loc)
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_WAIT_WAL);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_WAIT_WAL);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -2108,13 +2102,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2203,6 +2190,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
*/
if ((WalSndCaughtUp && !streamingDoneSending) || pq_is_send_pending())
{
+ int rc;
long sleeptime;
int wakeEvents;
@@ -2215,9 +2203,12 @@ WalSndLoop(WalSndSendDataCallback send_data)
wakeEvents |= WL_SOCKET_WRITEABLE;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_MAIN);
+ rc = WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_MAIN);
+
+ if (rc & WL_POSTMASTER_DEATH)
+ exit(1);
}
}
return;
--
2.16.2
Hi,
On 2018-04-11 11:57:20 +1200, Thomas Munro wrote:
Rebased, but I don't actually like this patch any more. Over in
another thread[1] I proposed that we should just make exit(1) the
default behaviour built into latch.c for those cases that don't want
to do something special (eg SyncRepWaitForLSN()), so we don't finish
up duplicating the ugly exit(1) code everywhere (or worse, forgetting
to). Tom Lane seemed to think that was an idea worth pursuing.I think what we need for PG12 is a patch that does that, and also
introduces a reused WaitEventSet object in several of these places.
Then eg SyncRepWaitForLSN() won't be interacting with contended kernel
objects every time (assuming an implementation like epoll or
eventually kqueue, completion ports etc is available).Then if pgarch_ArchiverCopyLoop() and HandleStartupProcInterrupts()
(ie loops without waiting) adopt a prctl(PR_SET_PDEATHSIG)-based
approach where available as suggested by Andres[2] or fall back to
polling a reusable WaitEventSet (timeout = 0), then there'd be no more
calls to PostmasterIsAlive() outside latch.c.
I'm still unconvinced by this. There's good reasons why code might be
busy-looping without checking the latch, and we shouldn't force code to
add more latch checks if unnecessary. Resetting the latch frequently can
actually increase the amount of context switches considerably.
- Andres
On Wed, Apr 11, 2018 at 12:03 PM, Andres Freund <andres@anarazel.de> wrote:
On 2018-04-11 11:57:20 +1200, Thomas Munro wrote:
Then if pgarch_ArchiverCopyLoop() and HandleStartupProcInterrupts()
(ie loops without waiting) adopt a prctl(PR_SET_PDEATHSIG)-based
approach where available as suggested by Andres[2] or fall back to
polling a reusable WaitEventSet (timeout = 0), then there'd be no more
calls to PostmasterIsAlive() outside latch.c.I'm still unconvinced by this. There's good reasons why code might be
busy-looping without checking the latch, and we shouldn't force code to
add more latch checks if unnecessary. Resetting the latch frequently can
actually increase the amount of context switches considerably.
What latch? There wouldn't be a latch in a WaitEventSet that is used
only to detect postmaster death.
I arrived at this idea via the realisation that the closest thing to
prctl(PR_SET_PDEATHSIG) on BSD-family systems today is
please-tell-my-kqueue-if-this-process-dies. It so happens that my
kqueue patch already uses that instead of the pipe to detect
postmaster death. The only problem is that you have to ask it, by
calling it kevent(). In a busy loop like those two, where there is no
other kind of waiting going on, you could do that by calling kevent()
with timeout = 0 to check the queue.
You could probably figure out a way to hide the
prctl(PR_SET_PDEATHSIG)-based approach inside the WaitEventSet code,
with a fast path that doesn't make any system calls if the only event
registered is postmaster death (you can just check the global variable
set by your signal handler). But I guess you wouldn't like the extra
function call so I guess you'd prefer to check the global variable
directly in the busy loop, in builds that have
prctl(PR_SET_PDEATHSIG).
--
Thomas Munro
http://www.enterprisedb.com
Hi,
On 2018-04-11 12:17:14 +1200, Thomas Munro wrote:
I arrived at this idea via the realisation that the closest thing to
prctl(PR_SET_PDEATHSIG) on BSD-family systems today is
please-tell-my-kqueue-if-this-process-dies. It so happens that my
kqueue patch already uses that instead of the pipe to detect
postmaster death. The only problem is that you have to ask it, by
calling it kevent(). In a busy loop like those two, where there is no
other kind of waiting going on, you could do that by calling kevent()
with timeout = 0 to check the queue.
Which is not cheap.
You could probably figure out a way to hide the
prctl(PR_SET_PDEATHSIG)-based approach inside the WaitEventSet code,
with a fast path that doesn't make any system calls if the only event
registered is postmaster death (you can just check the global variable
set by your signal handler). But I guess you wouldn't like the extra
function call so I guess you'd prefer to check the global variable
directly in the busy loop, in builds that have
prctl(PR_SET_PDEATHSIG).
Yea, I'd really want this to be a inline function of the style
static inline bool
PostmasterIsAlive(void)
{
if (!postmaster_possibly_dead)
return true;
return PostmasterIsAliveInternal();
}
I do not like the WES alternative because a special cased "just
postmaster death" WES seems to have absolutely no advantage over a
faster PostmasterIsAlive(). And using WES seems to make a cheap check
like the above significantly more complicated.
Greetings,
Andres Freund
On Wed, Apr 11, 2018 at 12:26 PM, Andres Freund <andres@anarazel.de> wrote:
On 2018-04-11 12:17:14 +1200, Thomas Munro wrote:
I arrived at this idea via the realisation that the closest thing to
prctl(PR_SET_PDEATHSIG) on BSD-family systems today is
please-tell-my-kqueue-if-this-process-dies. It so happens that my
kqueue patch already uses that instead of the pipe to detect
postmaster death. The only problem is that you have to ask it, by
calling it kevent(). In a busy loop like those two, where there is no
other kind of waiting going on, you could do that by calling kevent()
with timeout = 0 to check the queue.Which is not cheap.
Certainly, but I am reacting to reports via you of performance
problems coming from read(heavily_contended_fd) by saying: although we
can't avoid a syscall like Linux can in this case, we *can* avoid the
reportedly contended pipe mutex completely by reading only our own
process's kqueue. Combined with Heikki's proposal not to check every
single time through busy loops to reduce the syscall frequency, that
might be the optimal solution until some hypothetical
prctl(PR_SET_PDEATHSIG)-feature-match patch arrives. Just a thought.
--
Thomas Munro
http://www.enterprisedb.com
On Wed, Apr 11, 2018 at 12:47 PM, Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
On Wed, Apr 11, 2018 at 12:26 PM, Andres Freund <andres@anarazel.de> wrote:
On 2018-04-11 12:17:14 +1200, Thomas Munro wrote:
I arrived at this idea via the realisation that the closest thing to
prctl(PR_SET_PDEATHSIG) on BSD-family systems today is
please-tell-my-kqueue-if-this-process-dies. It so happens that my
kqueue patch already uses that instead of the pipe to detect
postmaster death. The only problem is that you have to ask it, by
calling it kevent(). In a busy loop like those two, where there is no
other kind of waiting going on, you could do that by calling kevent()
with timeout = 0 to check the queue.Which is not cheap.
After bouncing that idea around with a fellow pgsql-hacker off-list, I
take that idea back. It's a lot simpler and as cheap if not cheaper
to check getppid() == 1 or similar every Nth time through the busy
loop.
I heard another interesting idea -- you can use F_SETOWN + O_ASYNC to
ask for SIGIO to be delivered to you when the pipe is closed.
Unfortunately that'd require a different pipe for each backend so
wouldn't work for us.
--
Thomas Munro
http://www.enterprisedb.com
Hi,
I'd like to disentangle two related topics. For "I want
PostmasterIsAlive() to go faster using signals on platforms that can
support that", please see over here:
/messages/by-id/7261eb39-0369-f2f4-1bb5-62f3b6083b5e@iki.fi
For "I want to fix all the code that ignores the WL_POSTMASTER_DEATH
event and then calls PostmasterIsAlive() every time through its loop,
or fails to detect postmaster death at all", this is the thread
(unless someone sees a reason to reentangle them).
Here's a draft patch that does that. One contentious question is:
should you have to opt *in* to auto-exit-on-postmaster death? Andres
opined that you should. I actually think it's not so bad if you don't
have to do that, and instead have to opt out. I think of it as a kind
of 'process cancellation point' or a quiet PANIC that you can opt out
of. It's nice to remove the old boilerplate code without having to
add a new boilerplate event that you have to remember every time. Any
other opinions?
I'm not sure if the exit(1) vs proc_exit(1) distinction is important.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Exit-by-default-in-wait-routines-if-postmaster-dies.patchapplication/octet-stream; name=0001-Exit-by-default-in-wait-routines-if-postmaster-dies.patchDownload
From 3c4a303a198c20bf564ed36e8d7274db7c2880a6 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Exit by default in wait routines if postmaster dies.
Users of the WaitEventSet and WaitLatch() APIs can now choose between asking
for W_POSTMASTER_DEATH explicitly and then handling it, or not asking for it
and getting the new default behavior.
Update call sites to use the new simplified interface. In all cases where
the behavior was to exit(1) or proc_exit(1), remove that code and rely on the
default behavior. In some cases where WL_POSTMASTER_DEATH was requested but
apparently ignored, also use the new default behavior because that was
probably a bug. The remaining cases of explicit WL_POSTMASTER_DEATH events
are retained because they do something special when the postmaster dies.
Author: Thomas Munro
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
contrib/pg_prewarm/autoprewarm.c | 6 ++--
src/backend/access/transam/parallel.c | 6 +---
src/backend/access/transam/xlog.c | 6 ++--
src/backend/libpq/be-secure.c | 4 +--
src/backend/libpq/pqcomm.c | 9 +++--
src/backend/postmaster/autovacuum.c | 16 +++------
src/backend/postmaster/bgwriter.c | 11 ++----
src/backend/postmaster/checkpointer.c | 16 +++------
src/backend/postmaster/pgarch.c | 4 ++-
src/backend/postmaster/walwriter.c | 16 +++------
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 12 +------
src/backend/replication/logical/launcher.c | 24 +++----------
src/backend/replication/logical/tablesync.c | 29 ++++-----------
src/backend/replication/logical/worker.c | 7 +---
src/backend/replication/syncrep.c | 18 +++++-----
src/backend/replication/walreceiver.c | 20 ++---------
src/backend/replication/walsender.c | 29 ++-------------
src/backend/storage/ipc/latch.c | 41 ++++++++++++++++++++++
src/backend/storage/lmgr/condition_variable.c | 11 ------
src/backend/utils/init/miscinit.c | 6 ++--
src/include/libpq/libpq.h | 2 ++
src/test/modules/worker_spi/worker_spi.c | 6 +---
23 files changed, 108 insertions(+), 193 deletions(-)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index bb28e237d17..ee96ff032c9 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -219,7 +219,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET,
-1L,
PG_WAIT_EXTENSION);
}
@@ -248,15 +248,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 1d631b72755..a238ec65104 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -672,13 +672,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 08dc9ba031b..1ce15f09b2d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6120,7 +6120,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -11908,7 +11908,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12084,7 +12084,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index edfe2c0751c..206bf7d60b8 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -165,7 +165,7 @@ retry:
Assert(waitfor);
- ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
WAIT_EVENT_CLIENT_READ);
@@ -267,7 +267,7 @@ retry:
Assert(waitfor);
- ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
WAIT_EVENT_CLIENT_WRITE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index a4f6d4deeb4..4f5ce20cb22 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -184,6 +184,8 @@ static PQcommMethods PqCommSocketMethods = {
PQcommMethods *PqCommMethods = &PqCommSocketMethods;
WaitEventSet *FeBeWaitSet;
+int FeBeWaitSetSocketPos;
+int FeBeWaitSetLatchPos;
/* --------------------------------
@@ -221,9 +223,10 @@ pq_init(void)
#endif
FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, 3);
- AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, MyProcPort->sock,
- NULL, NULL);
- AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1, MyLatch, NULL);
+ FeBeWaitSetSocketPos = AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE,
+ MyProcPort->sock, NULL, NULL);
+ FeBeWaitSetLatchPos = AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1,
+ MyLatch, NULL);
AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, -1, NULL, NULL);
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 3b90b16daec..a566a01feeb 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -632,7 +632,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -648,23 +647,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index b7813d7a4fb..f1461197562 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -349,7 +349,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -376,20 +376,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 4b452e7cee6..5072d23e8c4 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -354,7 +354,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -555,17 +554,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 4fa3a3b0aaf..d36ff1b0d54 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -237,7 +237,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -290,17 +289,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index a79048d233d..8087352dc79 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1684,7 +1684,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index e4d261bd793..16dbd34d819 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,11 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
- WL_LATCH_SET,
+ WL_SOCKET_READABLE | WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 6ef333b7257..0848539a83e 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -209,13 +209,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -486,13 +482,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -534,13 +526,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -972,14 +960,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567d..e995c5383f9 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,9 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET | WL_TIMEOUT,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index aa7e27179e8..d28cdd538ea 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1254,15 +1254,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
wait_time = NAPTIME_PER_CYCLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_SOCKET_READABLE | WL_LATCH_SET | WL_TIMEOUT,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b9dab322d6b..b561bf94017 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -513,7 +513,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -534,15 +534,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -683,13 +674,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -716,7 +700,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 642e859439f..9a8792a7f94 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1205,7 +1205,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1213,13 +1213,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1300,13 +1293,6 @@ WalSndWaitForWal(XLogRecPtr loc)
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1400,8 +1386,7 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2108,13 +2093,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2206,8 +2184,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_TIMEOUT | WL_SOCKET_READABLE;
sleeptime = WalSndComputeSleeptime(now);
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index e6706f7fb80..f3d59307569 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -92,6 +92,12 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * If the client explicitly asks for WL_POSTMASTER_DEATH, then we'll
+ * return it. If otherwise we'll exit automatically.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -523,6 +529,9 @@ CreateWaitEventSet(MemoryContext context, int nevents)
char *data;
Size sz = 0;
+ /* Allow for the implicit WL_POSTMASTER_DEATH event. */
+ ++nevents;
+
/*
* Use MAXALIGN size/alignment to guarantee that later uses of memory are
* aligned correctly. E.g. epoll_event might need 8 byte alignment on some
@@ -591,6 +600,13 @@ CreateWaitEventSet(MemoryContext context, int nevents)
StaticAssertStmt(WSA_INVALID_EVENT == NULL, "");
#endif
+ /*
+ * Set up the default behavior for postmaster death. The caller can
+ * override this by explicitly adding a WL_POSTMASTER_DEATH event.
+ */
+ AddWaitEventToSet(set, WL_POSTMASTER_DEATH, -1, NULL, NULL);
+ set->exit_on_postmaster_death = true;
+
return set;
}
@@ -671,6 +687,17 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ /*
+ * If the caller explicitly asks for notification of postmaster death,
+ * then we don't need to do anything because we already installed one.
+ * We just need to disable the immediate exit behavior.
+ */
+ if (events == WL_POSTMASTER_DEATH && set->nevents > 0)
+ {
+ set->exit_on_postmaster_death = false;
+ return 0;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +953,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -1021,6 +1049,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller did not ask to
+ * handle that event.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..7ace6a897f7 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,8 +72,6 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
- NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
}
@@ -156,15 +154,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 03b28c3604a..a42e10f12ae 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -346,7 +346,8 @@ SwitchToSharedLatch(void)
MyLatch = &MyProc->procLatch;
if (FeBeWaitSet)
- ModifyWaitEvent(FeBeWaitSet, 1, WL_LATCH_SET, MyLatch);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET,
+ MyLatch);
/*
* Set the shared latch as the local one might have been set. This
@@ -365,7 +366,8 @@ SwitchBackToLocalLatch(void)
MyLatch = &LocalLatchData;
if (FeBeWaitSet)
- ModifyWaitEvent(FeBeWaitSet, 1, WL_LATCH_SET, MyLatch);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET,
+ MyLatch);
SetLatch(MyLatch);
}
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index a74ad521b5a..5611db97735 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -96,6 +96,8 @@ extern ssize_t secure_raw_write(Port *port, const void *ptr, size_t len);
extern bool ssl_loaded_verify_locations;
extern WaitEventSet *FeBeWaitSet;
+extern int FeBeWaitSetSocketPos;
+extern int FeBeWaitSetLatchPos;
/* GUCs */
extern char *SSLCipherSuites;
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..c991bf28f53 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.16.2
On Wed, Apr 18, 2018 at 6:55 PM, Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
Here's a draft patch that does that.
Here's a better one (the previous version could read past the end of
the occurred_events array).
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Exit-by-default-if-postmaster-dies-v2.patchapplication/octet-stream; name=0001-Exit-by-default-if-postmaster-dies-v2.patchDownload
From ff47c0c41af0d9b7c70733ade3c4af94ac506171 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Exit by default if postmaster dies.
Users of the WaitEventSet and WaitLatch() APIs can now choose between asking
for W_POSTMASTER_DEATH explicitly and then handling it, or not asking for it
and getting the new default behavior.
Update call sites to use the new simplified interface. In all cases where
the behavior was to exit(1) or proc_exit(1), remove that code and rely on the
default behavior. In some cases where WL_POSTMASTER_DEATH was requested but
apparently ignored, also use the new default behavior because that was
probably a bug. The remaining cases of explicit WL_POSTMASTER_DEATH events
are retained because they do something special when the postmaster dies.
Author: Thomas Munro
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
contrib/pg_prewarm/autoprewarm.c | 6 ++--
src/backend/access/transam/parallel.c | 6 +---
src/backend/access/transam/xlog.c | 6 ++--
src/backend/libpq/be-secure.c | 4 +--
src/backend/libpq/pqcomm.c | 9 +++--
src/backend/postmaster/autovacuum.c | 16 +++------
src/backend/postmaster/bgwriter.c | 11 ++----
src/backend/postmaster/checkpointer.c | 16 +++------
src/backend/postmaster/pgarch.c | 4 ++-
src/backend/postmaster/walwriter.c | 16 +++------
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 12 +------
src/backend/replication/logical/launcher.c | 24 +++----------
src/backend/replication/logical/tablesync.c | 29 ++++-----------
src/backend/replication/logical/worker.c | 7 +---
src/backend/replication/syncrep.c | 18 +++++-----
src/backend/replication/walreceiver.c | 20 ++---------
src/backend/replication/walsender.c | 29 ++-------------
src/backend/storage/ipc/latch.c | 42 +++++++++++++++++++++-
src/backend/storage/lmgr/condition_variable.c | 11 ------
src/backend/utils/init/miscinit.c | 6 ++--
src/include/libpq/libpq.h | 2 ++
src/test/modules/worker_spi/worker_spi.c | 6 +---
23 files changed, 108 insertions(+), 194 deletions(-)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index bb28e237d17..ee96ff032c9 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -219,7 +219,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET,
-1L,
PG_WAIT_EXTENSION);
}
@@ -248,15 +248,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 1d631b72755..a238ec65104 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -672,13 +672,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 08dc9ba031b..1ce15f09b2d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6120,7 +6120,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -11908,7 +11908,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12084,7 +12084,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index edfe2c0751c..206bf7d60b8 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -165,7 +165,7 @@ retry:
Assert(waitfor);
- ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
WAIT_EVENT_CLIENT_READ);
@@ -267,7 +267,7 @@ retry:
Assert(waitfor);
- ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, waitfor, NULL);
WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
WAIT_EVENT_CLIENT_WRITE);
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index a4f6d4deeb4..4f5ce20cb22 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -184,6 +184,8 @@ static PQcommMethods PqCommSocketMethods = {
PQcommMethods *PqCommMethods = &PqCommSocketMethods;
WaitEventSet *FeBeWaitSet;
+int FeBeWaitSetSocketPos;
+int FeBeWaitSetLatchPos;
/* --------------------------------
@@ -221,9 +223,10 @@ pq_init(void)
#endif
FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, 3);
- AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE, MyProcPort->sock,
- NULL, NULL);
- AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1, MyLatch, NULL);
+ FeBeWaitSetSocketPos = AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE,
+ MyProcPort->sock, NULL, NULL);
+ FeBeWaitSetLatchPos = AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, -1,
+ MyLatch, NULL);
AddWaitEventToSet(FeBeWaitSet, WL_POSTMASTER_DEATH, -1, NULL, NULL);
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 3b90b16daec..a566a01feeb 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -632,7 +632,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -648,23 +647,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index b7813d7a4fb..f1461197562 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -349,7 +349,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -376,20 +376,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 4b452e7cee6..5072d23e8c4 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -354,7 +354,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -555,17 +554,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 4fa3a3b0aaf..d36ff1b0d54 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -237,7 +237,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -290,17 +289,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index a79048d233d..8087352dc79 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1684,7 +1684,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index e4d261bd793..16dbd34d819 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,11 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
- WL_LATCH_SET,
+ WL_SOCKET_READABLE | WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 6ef333b7257..0848539a83e 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -209,13 +209,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -486,13 +482,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -534,13 +526,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -972,14 +960,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567d..e995c5383f9 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,9 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET | WL_TIMEOUT,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index aa7e27179e8..d28cdd538ea 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1254,15 +1254,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
wait_time = NAPTIME_PER_CYCLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_SOCKET_READABLE | WL_LATCH_SET | WL_TIMEOUT,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b9dab322d6b..b561bf94017 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -513,7 +513,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -534,15 +534,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -683,13 +674,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -716,7 +700,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 642e859439f..9a8792a7f94 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1205,7 +1205,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1213,13 +1213,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1300,13 +1293,6 @@ WalSndWaitForWal(XLogRecPtr loc)
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1400,8 +1386,7 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2108,13 +2093,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2206,8 +2184,7 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_TIMEOUT | WL_SOCKET_READABLE;
sleeptime = WalSndComputeSleeptime(now);
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index e6706f7fb80..84530d9f6b9 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -92,6 +92,12 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * If the client explicitly asks for WL_POSTMASTER_DEATH, then we'll
+ * return it. If otherwise we'll exit automatically.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -523,6 +529,9 @@ CreateWaitEventSet(MemoryContext context, int nevents)
char *data;
Size sz = 0;
+ /* Allow for the implicit WL_POSTMASTER_DEATH event. */
+ ++nevents;
+
/*
* Use MAXALIGN size/alignment to guarantee that later uses of memory are
* aligned correctly. E.g. epoll_event might need 8 byte alignment on some
@@ -591,6 +600,13 @@ CreateWaitEventSet(MemoryContext context, int nevents)
StaticAssertStmt(WSA_INVALID_EVENT == NULL, "");
#endif
+ /*
+ * Set up the default behavior for postmaster death. The caller can
+ * override this by explicitly adding a WL_POSTMASTER_DEATH event.
+ */
+ AddWaitEventToSet(set, WL_POSTMASTER_DEATH, -1, NULL, NULL);
+ set->exit_on_postmaster_death = true;
+
return set;
}
@@ -671,6 +687,17 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ /*
+ * If the caller explicitly asks for notification of postmaster death,
+ * then we don't need to do anything because we already installed one.
+ * We just need to disable the immediate exit behavior.
+ */
+ if (events == WL_POSTMASTER_DEATH && set->nevents > 0)
+ {
+ set->exit_on_postmaster_death = false;
+ return 0;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +953,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -986,7 +1014,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1021,6 +1048,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller did not ask to
+ * handle that event.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..7ace6a897f7 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,8 +72,6 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
- NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
}
@@ -156,15 +154,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 03b28c3604a..a42e10f12ae 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -346,7 +346,8 @@ SwitchToSharedLatch(void)
MyLatch = &MyProc->procLatch;
if (FeBeWaitSet)
- ModifyWaitEvent(FeBeWaitSet, 1, WL_LATCH_SET, MyLatch);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET,
+ MyLatch);
/*
* Set the shared latch as the local one might have been set. This
@@ -365,7 +366,8 @@ SwitchBackToLocalLatch(void)
MyLatch = &LocalLatchData;
if (FeBeWaitSet)
- ModifyWaitEvent(FeBeWaitSet, 1, WL_LATCH_SET, MyLatch);
+ ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetLatchPos, WL_LATCH_SET,
+ MyLatch);
SetLatch(MyLatch);
}
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index a74ad521b5a..5611db97735 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -96,6 +96,8 @@ extern ssize_t secure_raw_write(Port *port, const void *ptr, size_t len);
extern bool ssl_loaded_verify_locations;
extern WaitEventSet *FeBeWaitSet;
+extern int FeBeWaitSetSocketPos;
+extern int FeBeWaitSetLatchPos;
/* GUCs */
extern char *SSLCipherSuites;
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..c991bf28f53 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.16.2
On 18/04/18 09:55, Thomas Munro wrote:
Here's a draft patch that does that. One contentious question is:
should you have to opt *in* to auto-exit-on-postmaster death? Andres
opined that you should. I actually think it's not so bad if you don't
have to do that, and instead have to opt out. I think of it as a kind
of 'process cancellation point' or a quiet PANIC that you can opt out
of. It's nice to remove the old boilerplate code without having to
add a new boilerplate event that you have to remember every time. Any
other opinions?
Hmm. Exiting on postmaster death by default does feel a bit too magical
to me. But as your patch points out, there are currently no places where
you *don't* want to exit on postmaster death, some callers just prefer
to handle it themselves. And I like having a default or something to
make sure that all call sites in the future will also exit quickly.
I'd suggest that we add a new WL_EXIT_ON_POSTMASTER_DEATH flag, making
it opt-on. But add an assertion in WaitLatchOrSocket:
Assert ((wakeEvents & (WL_EXIT_POSTMASTER_DEATH | WL_POSTMASTER_DEATH))
!= 0);
That ensures that all callers either use WL_EXIT_ON_POSTMASTER_DEATH, or
WL_POSTMASTER_DEATH to handle it in the caller. Having to specify
WL_EXIT_ON_POSTMASTER_DEATH reminds you that the call might exit(), so
if that's not what you want, you need to do something else. But the
assertion makes sure that all callers deal with postmaster death in some
way.
- Heikki
On Sat, Jul 14, 2018 at 5:34 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 18/04/18 09:55, Thomas Munro wrote:
Here's a draft patch that does that. One contentious question is:
should you have to opt *in* to auto-exit-on-postmaster death? Andres
opined that you should. I actually think it's not so bad if you don't
have to do that, and instead have to opt out. I think of it as a kind
of 'process cancellation point' or a quiet PANIC that you can opt out
of. It's nice to remove the old boilerplate code without having to
add a new boilerplate event that you have to remember every time. Any
other opinions?Hmm. Exiting on postmaster death by default does feel a bit too magical to
me. But as your patch points out, there are currently no places where you
*don't* want to exit on postmaster death, some callers just prefer to handle
it themselves. And I like having a default or something to make sure that
all call sites in the future will also exit quickly.I'd suggest that we add a new WL_EXIT_ON_POSTMASTER_DEATH flag, making it
opt-on.
Ok, it's now 2 against 1. So here's a version that uses an explicit
WL_EXIT_ON_PM_DEATH value. I like that name because it's shorter and
more visually distinctive (harder to confuse with
WL_POSTMASTER_DEATH).
But add an assertion in WaitLatchOrSocket:
Assert ((wakeEvents & (WL_EXIT_POSTMASTER_DEATH | WL_POSTMASTER_DEATH)) !=
0);
Ok. Done for the WaitLatchXXX() interface. The WaitEventSet
interface (rarely used directly) is less amenable to that change.
Here are some of the places I had to add WL_EXIT_ON_PM_DEATH:
gather_readnext(), shm_mq_send_bytes(), shm_mq_receive_bytes(),
shm_mq_wait_internal(), ProcSleep(), ProcWaitForSignal(), pg_sleep(),
pgfdw_get_result().
Was it intentional that any of those places don't currently exit on
postmaster vaporisation?
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v3.patchapplication/octet-stream; name=0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v3.patchDownload
From 83f5a6fa3e4c97cf12e57c40e095e212bddf81bb Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
Author: Thomas Munro
Reviewed-by: Heikki Linnakangas
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
contrib/pg_prewarm/autoprewarm.c | 6 +--
contrib/postgres_fdw/connection.c | 6 ++-
src/backend/access/transam/parallel.c | 8 +---
src/backend/access/transam/xlog.c | 6 +--
src/backend/executor/nodeGather.c | 3 +-
src/backend/libpq/pqmq.c | 2 +-
src/backend/postmaster/autovacuum.c | 16 ++------
src/backend/postmaster/bgwriter.c | 11 +-----
src/backend/postmaster/checkpointer.c | 16 ++------
src/backend/postmaster/pgarch.c | 4 +-
src/backend/postmaster/syslogger.c | 2 +
src/backend/postmaster/walwriter.c | 16 ++------
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 13 +------
src/backend/replication/logical/launcher.c | 24 ++----------
src/backend/replication/logical/tablesync.c | 30 ++++----------
src/backend/replication/logical/worker.c | 6 +--
src/backend/replication/syncrep.c | 18 +++++----
src/backend/replication/walreceiver.c | 20 +---------
src/backend/replication/walsender.c | 31 +++------------
src/backend/storage/ipc/latch.c | 39 ++++++++++++++++++-
src/backend/storage/ipc/shm_mq.c | 9 +++--
src/backend/storage/lmgr/condition_variable.c | 11 +-----
src/backend/storage/lmgr/proc.c | 4 +-
src/backend/utils/adt/misc.c | 2 +-
src/include/storage/latch.h | 3 +-
src/test/modules/test_shm_mq/setup.c | 3 +-
src/test/modules/test_shm_mq/test.c | 3 +-
src/test/modules/worker_spi/worker_spi.c | 6 +--
29 files changed, 121 insertions(+), 199 deletions(-)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index cc5e2dd89cd..06eaa3b1010 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -220,7 +220,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
}
@@ -249,15 +249,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index fe4893a8e05..a6509932dcf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -546,7 +546,8 @@ pgfdw_get_result(PGconn *conn, const char *query)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
-1L, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
@@ -1152,7 +1153,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
cur_timeout, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 4e32cfff500..03b0adcb5e4 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -665,13 +665,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -788,7 +784,7 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
}
}
- WaitLatch(MyLatch, WL_LATCH_SET, -1,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
WAIT_EVENT_PARALLEL_FINISH);
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4049deb968e..ab48bad4385 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6178,7 +6178,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -12058,7 +12058,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12234,7 +12234,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index cdc9c51bd15..0c68fa5da7b 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -361,7 +361,8 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_EXECUTE_GATHER);
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 201075dd477..77258b97ea6 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,7 +168,7 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_MQ_PUT_MESSAGE);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 78e4c85f5d7..91309b65c87 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -632,7 +632,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -648,23 +647,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index d5ce685e54f..abf2ef08362 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -349,7 +349,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -376,20 +376,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 0950ada6019..610e7ec01ef 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -354,7 +354,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -555,17 +554,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 58b759f305f..7f20772c5d7 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -433,6 +433,7 @@ SysLoggerMain(int argc, char *argv[])
*/
#ifndef WIN32
rc = WaitLatchOrSocket(MyLatch,
+ WL_EXIT_ON_PM_DEATH |
WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
syslogPipe[0],
cur_timeout,
@@ -486,6 +487,7 @@ SysLoggerMain(int argc, char *argv[])
LeaveCriticalSection(&sysloggerSection);
(void) WaitLatch(MyLatch,
+ WL_EXIT_ON_PM_DEATH |
WL_LATCH_SET | cur_flags,
cur_timeout,
WAIT_EVENT_SYSLOGGER_MAIN);
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 688d5b5b80b..8b5e1647224 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -237,7 +237,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -290,17 +289,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 3f1eae38a92..4b671327fd8 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1686,7 +1686,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index bd489061602..ca038640dff 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
- WL_LATCH_SET | io_flag,
+ WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,12 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index ada16adb67b..4833ff9d48c 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -221,13 +221,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -498,13 +494,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -546,13 +538,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -1072,14 +1060,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567d..159234ef3c7 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,10 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 0d2b795e392..fa5251a0023 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1255,14 +1255,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
rc = WaitLatchOrSocket(MyLatch,
WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 987bb84683c..7818f243ab5 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -513,7 +513,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -534,15 +534,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -683,13 +674,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -716,7 +700,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 3a0106bc933..fc3de99143c 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1205,7 +1205,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1213,13 +1213,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1300,13 +1293,6 @@ WalSndWaitForWal(XLogRecPtr loc)
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1400,8 +1386,8 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
+ WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2108,13 +2094,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2206,8 +2185,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH | WL_TIMEOUT |
+ WL_SOCKET_READABLE;
sleeptime = WalSndComputeSleeptime(now);
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index f6dda9cc9ac..7a76493269a 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -92,6 +92,13 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * WL_EXIT_ON_PM_DEATH is converted to WL_POSTMASTER_DEATH, but this flag
+ * is set so that we'll exit immediately if postmaster death is detected,
+ * instead of returning.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -370,10 +377,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
(Latch *) latch, NULL);
+ /* Postmaster-managed callers must handle postmaster death somehow. */
+ Assert(!IsUnderPostmaster ||
+ (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
+ (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
+
if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
NULL, NULL);
+ if (wakeEvents & WL_EXIT_ON_PM_DEATH && IsUnderPostmaster)
+ AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+ NULL, NULL);
+
if (wakeEvents & WL_SOCKET_MASK)
{
int ev;
@@ -562,6 +578,7 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->latch = NULL;
set->nevents_space = nevents;
+ set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
#ifdef EPOLL_CLOEXEC
@@ -646,6 +663,7 @@ FreeWaitEventSet(WaitEventSet *set)
* - WL_SOCKET_CONNECTED: Wait for socket connection to be established,
* can be combined with other WL_SOCKET_* events (on non-Windows
* platforms, this is the same as WL_SOCKET_WRITEABLE)
+ * - WL_EXIT_ON_PM_DEATH: Exit immediately if the postmaster dies
*
* Returns the offset in WaitEventSet->events (starting from 0), which can be
* used to modify previously added wait events using ModifyWaitEvent().
@@ -671,6 +689,12 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ if (events == WL_EXIT_ON_PM_DEATH)
+ {
+ events = WL_POSTMASTER_DEATH;
+ set->exit_on_postmaster_death = true;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +950,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -986,7 +1011,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1021,6 +1045,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller asked for
+ * automatic exit in that case.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index fde71afd479..0b9ecf81451 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -949,7 +949,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_SEND);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1093,7 +1094,8 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_RECEIVE);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1181,7 +1183,8 @@ shm_mq_wait_internal(shm_mq *mq, PGPROC **ptr, BackgroundWorkerHandle *handle)
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_INTERNAL);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..851c09ce7ad 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,7 +72,7 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+ AddWaitEventToSet(new_event_set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
@@ -156,15 +156,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6f30e082b26..2394f473c6a 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1261,7 +1261,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
@@ -1774,7 +1774,7 @@ CheckDeadLockAlert(void)
void
ProcWaitForSignal(uint32 wait_event_info)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, wait_event_info);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index b24dece23f8..81c72d8bf80 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -573,7 +573,7 @@ pg_sleep(PG_FUNCTION_ARGS)
break;
(void) WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_ms,
WAIT_EVENT_PG_SLEEP);
ResetLatch(MyLatch);
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index a4bcb48874a..be41d834312 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -126,8 +126,9 @@ typedef struct Latch
#define WL_SOCKET_WRITEABLE (1 << 2)
#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */
#define WL_POSTMASTER_DEATH (1 << 4)
+#define WL_EXIT_ON_PM_DEATH (1 << 5)
#ifdef WIN32
-#define WL_SOCKET_CONNECTED (1 << 5)
+#define WL_SOCKET_CONNECTED (1 << 6)
#else
/* avoid having to to deal with case on platforms not requiring it */
#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 97e8617b3e9..af88110885d 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -280,7 +280,8 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index ebab9866017..b9621c294d1 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -231,7 +231,8 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..52a3208527e 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.17.0
Hello.
At Wed, 18 Jul 2018 14:02:47 +1200, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=3t57KBxb90CTqnDZiSTnTq3jwxZUc0zaFDiaOkGQqNxA@mail.gmail.com>
On Sat, Jul 14, 2018 at 5:34 AM, Heikki Linnakangas <hlinnaka@iki.fi> wrote:
On 18/04/18 09:55, Thomas Munro wrote:
Here's a draft patch that does that. One contentious question is:
should you have to opt *in* to auto-exit-on-postmaster death? Andres
opined that you should. I actually think it's not so bad if you don't
have to do that, and instead have to opt out. I think of it as a kind
of 'process cancellation point' or a quiet PANIC that you can opt out
of. It's nice to remove the old boilerplate code without having to
add a new boilerplate event that you have to remember every time. Any
other opinions?Hmm. Exiting on postmaster death by default does feel a bit too magical to
me. But as your patch points out, there are currently no places where you
*don't* want to exit on postmaster death, some callers just prefer to handle
it themselves. And I like having a default or something to make sure that
all call sites in the future will also exit quickly.I'd suggest that we add a new WL_EXIT_ON_POSTMASTER_DEATH flag, making it
opt-on.Ok, it's now 2 against 1. So here's a version that uses an explicit
WL_EXIT_ON_PM_DEATH value. I like that name because it's shorter and
more visually distinctive (harder to confuse with
WL_POSTMASTER_DEATH).But add an assertion in WaitLatchOrSocket:
Assert ((wakeEvents & (WL_EXIT_POSTMASTER_DEATH | WL_POSTMASTER_DEATH)) !=
0);Ok. Done for the WaitLatchXXX() interface. The WaitEventSet
interface (rarely used directly) is less amenable to that change.Here are some of the places I had to add WL_EXIT_ON_PM_DEATH:
gather_readnext(), shm_mq_send_bytes(), shm_mq_receive_bytes(),
shm_mq_wait_internal(), ProcSleep(), ProcWaitForSignal(), pg_sleep(),
pgfdw_get_result().Was it intentional that any of those places don't currently exit on
postmaster vaporisation?
I think that backends are supposed to complete running query even
if postmaster dies meanwhile and currently that seems
true. pgfdw_get_result seems to be following the policy. Perhaps
it's the same for all of the functions listed above.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
On Wed, Jul 18, 2018 at 8:30 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
At Wed, 18 Jul 2018 14:02:47 +1200, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=3t57KBxb90CTqnDZiSTnTq3jwxZUc0zaFDiaOkGQqNxA@mail.gmail.com>
Here are some of the places I had to add WL_EXIT_ON_PM_DEATH:
gather_readnext(), shm_mq_send_bytes(), shm_mq_receive_bytes(),
shm_mq_wait_internal(), ProcSleep(), ProcWaitForSignal(), pg_sleep(),
pgfdw_get_result().Was it intentional that any of those places don't currently exit on
postmaster vaporisation?I think that backends are supposed to complete running query even
if postmaster dies meanwhile and currently that seems
true. pgfdw_get_result seems to be following the policy. Perhaps
it's the same for all of the functions listed above.
Hmm. Why wait any longer? The cluster is broken. Is there some
correctness reason to defer shutdown in any of these places?
While looking for earlier discussion that might explain why some
places ignored it, I came across this email from Andres, saying the
same thing.
/messages/by-id/20160321093534.inkduxvpirs5n44j@alap3.anarazel.de
He mentioned that syslogger.c is a special case. In my patch I added
WL_EXIT_ON_PM_DEATH to SysLoggerMain()'s WaitLatch*() calls, because I
have to or the new assertion fails. Hmm, yeah, that's not great
because it might discard the last words of other backends. So here is
a new version that treats syslogger.c specially and may have other
performance benefits.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v2.patchapplication/octet-stream; name=0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v2.patchDownload
From db7b7567527b8107ced821d4dfb25b8e02d6c22d Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll().
Author: Thomas Munro
Reviewed-by: Heikki Linnakangas
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
contrib/pg_prewarm/autoprewarm.c | 6 +--
contrib/postgres_fdw/connection.c | 6 ++-
src/backend/access/transam/parallel.c | 8 +---
src/backend/access/transam/xlog.c | 6 +--
src/backend/executor/nodeGather.c | 3 +-
src/backend/libpq/pqmq.c | 2 +-
src/backend/postmaster/autovacuum.c | 16 ++------
src/backend/postmaster/bgwriter.c | 11 +-----
src/backend/postmaster/checkpointer.c | 16 ++------
src/backend/postmaster/pgarch.c | 4 +-
src/backend/postmaster/syslogger.c | 33 +++++++++++-----
src/backend/postmaster/walwriter.c | 16 ++------
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 13 +------
src/backend/replication/logical/launcher.c | 24 ++----------
src/backend/replication/logical/tablesync.c | 30 ++++----------
src/backend/replication/logical/worker.c | 6 +--
src/backend/replication/syncrep.c | 18 +++++----
src/backend/replication/walreceiver.c | 20 +---------
src/backend/replication/walsender.c | 31 +++------------
src/backend/storage/ipc/latch.c | 39 ++++++++++++++++++-
src/backend/storage/ipc/shm_mq.c | 9 +++--
src/backend/storage/lmgr/condition_variable.c | 11 +-----
src/backend/storage/lmgr/proc.c | 4 +-
src/backend/utils/adt/misc.c | 2 +-
src/include/storage/latch.h | 3 +-
src/test/modules/test_shm_mq/setup.c | 3 +-
src/test/modules/test_shm_mq/test.c | 3 +-
src/test/modules/worker_spi/worker_spi.c | 6 +--
29 files changed, 142 insertions(+), 209 deletions(-)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index cc5e2dd89cd..06eaa3b1010 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -220,7 +220,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
}
@@ -249,15 +249,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index fe4893a8e05..a6509932dcf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -546,7 +546,8 @@ pgfdw_get_result(PGconn *conn, const char *query)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
-1L, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
@@ -1152,7 +1153,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
cur_timeout, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 30ddf94c952..3eb1f0dffc3 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -664,13 +664,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -787,7 +783,7 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
}
}
- WaitLatch(MyLatch, WL_LATCH_SET, -1,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
WAIT_EVENT_PARALLEL_FINISH);
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 3ee6d5c4676..a84066eeb77 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6183,7 +6183,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -12090,7 +12090,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12266,7 +12266,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index cdc9c51bd15..0c68fa5da7b 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -361,7 +361,8 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_EXECUTE_GATHER);
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 201075dd477..77258b97ea6 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,7 +168,7 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_MQ_PUT_MESSAGE);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 1d9cfc63d22..1e92565a521 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -628,7 +628,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -644,23 +643,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 960d3de2040..4b0ea70bd69 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -339,7 +339,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -366,20 +366,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index de1b22d0455..af80099cf96 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -344,7 +344,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -545,17 +544,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 58b759f305f..43fea2392e4 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -165,6 +165,7 @@ SysLoggerMain(int argc, char *argv[])
char *currentLogFilename;
int currentLogRotationAge;
pg_time_t now;
+ WaitEventSet *wes;
now = MyStartTime;
@@ -286,6 +287,22 @@ SysLoggerMain(int argc, char *argv[])
set_next_rotation_time();
update_metainfo_datafile();
+ /*
+ * Set up a reusable WaitEventSet object we'll use to wait for our latch,
+ * and (except on Windows) our socket.
+ *
+ * Unlike all other postmaster child processes, we'll ignore postmaster
+ * death because we want to collect final log output from all backends and
+ * then exit last. We'll do that by running until we see EOF on the
+ * syslog pipe, which implies that all other backends have exited
+ * (including the postmaster).
+ */
+ wes = CreateWaitEventSet(CurrentMemoryContext, 2);
+ AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL);
+#ifndef WIN32
+ AddWaitEventToSet(wes, WL_SOCKET_READABLE, syslogPipe[0], NULL, NULL);
+#endif
+
/* main worker loop */
for (;;)
{
@@ -293,6 +310,7 @@ SysLoggerMain(int argc, char *argv[])
int size_rotation_for = 0;
long cur_timeout;
int cur_flags;
+ WaitEvent event;
#ifndef WIN32
int rc;
@@ -432,13 +450,10 @@ SysLoggerMain(int argc, char *argv[])
* Sleep until there's something to do
*/
#ifndef WIN32
- rc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
- syslogPipe[0],
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ rc = WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
- if (rc & WL_SOCKET_READABLE)
+ if (rc == 1 && event.events == WL_SOCKET_READABLE)
{
int bytesRead;
@@ -485,10 +500,8 @@ SysLoggerMain(int argc, char *argv[])
*/
LeaveCriticalSection(&sysloggerSection);
- (void) WaitLatch(MyLatch,
- WL_LATCH_SET | cur_flags,
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ (void) WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
EnterCriticalSection(&sysloggerSection);
#endif /* WIN32 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index eceed1bf882..70859ee3fe0 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -227,7 +227,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -280,17 +279,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 3f1eae38a92..4b671327fd8 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1686,7 +1686,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index bd489061602..ca038640dff 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
- WL_LATCH_SET | io_flag,
+ WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,12 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index ada16adb67b..4833ff9d48c 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -221,13 +221,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -498,13 +494,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -546,13 +538,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -1072,14 +1060,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567d..159234ef3c7 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,10 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 6ca6cdcacfa..db70a51defe 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1255,14 +1255,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
rc = WaitLatchOrSocket(MyLatch,
WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7c292d8071b..df29eeb4835 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -507,7 +507,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -528,15 +528,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -677,13 +668,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -710,7 +694,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index e8f4f37e5ce..cc16c5dacdd 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1211,7 +1211,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1219,13 +1219,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1306,13 +1299,6 @@ WalSndWaitForWal(XLogRecPtr loc)
long sleeptime;
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1406,8 +1392,8 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(now);
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
+ WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2114,13 +2100,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
{
TimestampTz now;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2212,8 +2191,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH | WL_TIMEOUT |
+ WL_SOCKET_READABLE;
sleeptime = WalSndComputeSleeptime(now);
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index f6dda9cc9ac..7a76493269a 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -92,6 +92,13 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * WL_EXIT_ON_PM_DEATH is converted to WL_POSTMASTER_DEATH, but this flag
+ * is set so that we'll exit immediately if postmaster death is detected,
+ * instead of returning.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -370,10 +377,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
(Latch *) latch, NULL);
+ /* Postmaster-managed callers must handle postmaster death somehow. */
+ Assert(!IsUnderPostmaster ||
+ (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
+ (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
+
if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
NULL, NULL);
+ if (wakeEvents & WL_EXIT_ON_PM_DEATH && IsUnderPostmaster)
+ AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+ NULL, NULL);
+
if (wakeEvents & WL_SOCKET_MASK)
{
int ev;
@@ -562,6 +578,7 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->latch = NULL;
set->nevents_space = nevents;
+ set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
#ifdef EPOLL_CLOEXEC
@@ -646,6 +663,7 @@ FreeWaitEventSet(WaitEventSet *set)
* - WL_SOCKET_CONNECTED: Wait for socket connection to be established,
* can be combined with other WL_SOCKET_* events (on non-Windows
* platforms, this is the same as WL_SOCKET_WRITEABLE)
+ * - WL_EXIT_ON_PM_DEATH: Exit immediately if the postmaster dies
*
* Returns the offset in WaitEventSet->events (starting from 0), which can be
* used to modify previously added wait events using ModifyWaitEvent().
@@ -671,6 +689,12 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ if (events == WL_EXIT_ON_PM_DEATH)
+ {
+ events = WL_POSTMASTER_DEATH;
+ set->exit_on_postmaster_death = true;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +950,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -986,7 +1011,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1021,6 +1045,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller asked for
+ * automatic exit in that case.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index fde71afd479..0b9ecf81451 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -949,7 +949,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_SEND);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1093,7 +1094,8 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_RECEIVE);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1181,7 +1183,8 @@ shm_mq_wait_internal(shm_mq *mq, PGPROC **ptr, BackgroundWorkerHandle *handle)
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_INTERNAL);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..851c09ce7ad 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,7 +72,7 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+ AddWaitEventToSet(new_event_set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
@@ -156,15 +156,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6f30e082b26..2394f473c6a 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1261,7 +1261,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
@@ -1774,7 +1774,7 @@ CheckDeadLockAlert(void)
void
ProcWaitForSignal(uint32 wait_event_info)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, wait_event_info);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index b24dece23f8..81c72d8bf80 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -573,7 +573,7 @@ pg_sleep(PG_FUNCTION_ARGS)
break;
(void) WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_ms,
WAIT_EVENT_PG_SLEEP);
ResetLatch(MyLatch);
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index fd8735b7f5f..039a82e1a3a 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -126,8 +126,9 @@ typedef struct Latch
#define WL_SOCKET_WRITEABLE (1 << 2)
#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */
#define WL_POSTMASTER_DEATH (1 << 4)
+#define WL_EXIT_ON_PM_DEATH (1 << 5)
#ifdef WIN32
-#define WL_SOCKET_CONNECTED (1 << 5)
+#define WL_SOCKET_CONNECTED (1 << 6)
#else
/* avoid having to deal with case on platforms not requiring it */
#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 97e8617b3e9..af88110885d 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -280,7 +280,8 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index ebab9866017..b9621c294d1 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -231,7 +231,8 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..52a3208527e 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.17.0
At Thu, 19 Jul 2018 16:58:30 +1200, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=1R__sW-CTByAi+cFUXX8tJu8MTNdeQGZ4L-x5gZ4mxNA@mail.gmail.com>
On Wed, Jul 18, 2018 at 8:30 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:At Wed, 18 Jul 2018 14:02:47 +1200, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=3t57KBxb90CTqnDZiSTnTq3jwxZUc0zaFDiaOkGQqNxA@mail.gmail.com>
Here are some of the places I had to add WL_EXIT_ON_PM_DEATH:
gather_readnext(), shm_mq_send_bytes(), shm_mq_receive_bytes(),
shm_mq_wait_internal(), ProcSleep(), ProcWaitForSignal(), pg_sleep(),
pgfdw_get_result().Was it intentional that any of those places don't currently exit on
postmaster vaporisation?I think that backends are supposed to complete running query even
if postmaster dies meanwhile and currently that seems
true. pgfdw_get_result seems to be following the policy. Perhaps
it's the same for all of the functions listed above.Hmm. Why wait any longer? The cluster is broken. Is there some
correctness reason to defer shutdown in any of these places?
Well, please don't get me wrong. I don't object to backends' exit
on postmaster death, rather I'm for it. Maybe the idea of mine
came from somthing like this (perhaps newer one), in the meaning
of just why it is working in that way now.
/messages/by-id/21877.1294946166@sss.pgh.pa.us
While looking for earlier discussion that might explain why some
places ignored it, I came across this email from Andres, saying the
same thing./messages/by-id/20160321093534.inkduxvpirs5n44j@alap3.anarazel.de
He mentioned that syslogger.c is a special case. In my patch I added
WL_EXIT_ON_PM_DEATH to SysLoggerMain()'s WaitLatch*() calls, because I
have to or the new assertion fails. Hmm, yeah, that's not great
because it might discard the last words of other backends. So here is
a new version that treats syslogger.c specially and may have other
performance benefits.
Yeah. That seems good. Couldn't we reuse prepared WaitEventSet in
other places? For example PgstatCollectorMain has the same
characteristics, where WaitLatchOrSocket is used with fixed
parameters and waiting on a socket which gets frequent receipts.
# Is it intentional that the patch doesn't touch pgstat.c?
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
On Thu, Jul 19, 2018 at 10:30 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
Hmm. Why wait any longer? The cluster is broken. Is there some
correctness reason to defer shutdown in any of these places?Well, please don't get me wrong. I don't object to backends' exit
on postmaster death, rather I'm for it. Maybe the idea of mine
came from somthing like this (perhaps newer one), in the meaning
of just why it is working in that way now.
Thanks, that was interesting. It's from *before* the pipe solution
was implemented though so I'm not sure it's relevant: the
exit-as-soon-as-possible camp won that battle, we just missed a few
places.
He mentioned that syslogger.c is a special case. In my patch I added
WL_EXIT_ON_PM_DEATH to SysLoggerMain()'s WaitLatch*() calls, because I
have to or the new assertion fails. Hmm, yeah, that's not great
because it might discard the last words of other backends. So here is
a new version that treats syslogger.c specially and may have other
performance benefits.Yeah. That seems good. Couldn't we reuse prepared WaitEventSet in
other places? For example PgstatCollectorMain has the same
characteristics, where WaitLatchOrSocket is used with fixed
parameters and waiting on a socket which gets frequent receipts.
+1, but I'm considering that to be a separate project, or I'll never
get this patch committed. It may be possible to have a small number
of them reused in many places, and it may be possible for
WaitLatchXXX() to reuse them automatically (so we don't have to change
every call site).
# Is it intentional that the patch doesn't touch pgstat.c?
Yes. pgstat.c still uses WL_POSTMASTER_DEATH because it does
something special: it calls pgstat_write_statsfiles() before it exits.
--
Thomas Munro
http://www.enterprisedb.com
On Thu, Jul 19, 2018 at 11:51 PM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
On Thu, Jul 19, 2018 at 10:30 PM, Kyotaro HORIGUCHI
Yeah. That seems good. Couldn't we reuse prepared WaitEventSet in
other places? For example PgstatCollectorMain has the same
characteristics, where WaitLatchOrSocket is used with fixed
parameters and waiting on a socket which gets frequent receipts.+1, but I'm considering that to be a separate project, or I'll never
get this patch committed. It may be possible to have a small number
of them reused in many places, and it may be possible for
WaitLatchXXX() to reuse them automatically (so we don't have to change
every call site).# Is it intentional that the patch doesn't touch pgstat.c?
Yes. pgstat.c still uses WL_POSTMASTER_DEATH because it does
something special: it calls pgstat_write_statsfiles() before it exits.
Rebased.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v3.patchapplication/octet-stream; name=0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v3.patchDownload
From 65ead81bf77bc80a403bcfb367ab92d3af90f130 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll().
Author: Thomas Munro
Reviewed-by: Heikki Linnakangas, Kyotaro Horiguchi
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
contrib/pg_prewarm/autoprewarm.c | 6 +--
contrib/postgres_fdw/connection.c | 6 ++-
src/backend/access/transam/parallel.c | 8 +---
src/backend/access/transam/xlog.c | 6 +--
src/backend/executor/nodeGather.c | 3 +-
src/backend/libpq/pqmq.c | 2 +-
src/backend/postmaster/autovacuum.c | 16 ++------
src/backend/postmaster/bgwriter.c | 11 +-----
src/backend/postmaster/checkpointer.c | 16 ++------
src/backend/postmaster/pgarch.c | 4 +-
src/backend/postmaster/syslogger.c | 33 +++++++++++-----
src/backend/postmaster/walwriter.c | 16 ++------
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 13 +------
src/backend/replication/logical/launcher.c | 24 ++----------
src/backend/replication/logical/tablesync.c | 30 ++++----------
src/backend/replication/logical/worker.c | 6 +--
src/backend/replication/syncrep.c | 18 +++++----
src/backend/replication/walreceiver.c | 20 +---------
src/backend/replication/walsender.c | 31 +++------------
src/backend/storage/ipc/latch.c | 39 ++++++++++++++++++-
src/backend/storage/ipc/shm_mq.c | 9 +++--
src/backend/storage/lmgr/condition_variable.c | 11 +-----
src/backend/storage/lmgr/proc.c | 4 +-
src/backend/utils/adt/misc.c | 2 +-
src/include/storage/latch.h | 3 +-
src/test/modules/test_shm_mq/setup.c | 3 +-
src/test/modules/test_shm_mq/test.c | 3 +-
src/test/modules/worker_spi/worker_spi.c | 6 +--
29 files changed, 142 insertions(+), 209 deletions(-)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index cc5e2dd89cd..06eaa3b1010 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -220,7 +220,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
}
@@ -249,15 +249,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index fe4893a8e05..a6509932dcf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -546,7 +546,8 @@ pgfdw_get_result(PGconn *conn, const char *query)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
-1L, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
@@ -1152,7 +1153,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
cur_timeout, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index c1681184670..09c5e3b5393 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -676,13 +676,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -799,7 +795,7 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
}
}
- WaitLatch(MyLatch, WL_LATCH_SET, -1,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
WAIT_EVENT_PARALLEL_FINISH);
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 65db2e48d88..31b45215d27 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6208,7 +6208,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -12113,7 +12113,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12289,7 +12289,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 4a700b7b30e..b1459b4b872 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -364,7 +364,8 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_EXECUTE_GATHER);
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 4fbc6b5115d..bb788fbd565 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,7 +168,7 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_MQ_PUT_MESSAGE);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 978089575b8..2d7c65b7cbb 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -628,7 +628,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -644,23 +643,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index b1e9bb2c537..3da7bdac1de 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -339,7 +339,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -366,20 +366,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 1a033093c53..8c2cdda3f5a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -344,7 +344,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -545,17 +544,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 29bdcec8958..b0aa38f0ae8 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -168,6 +168,7 @@ SysLoggerMain(int argc, char *argv[])
char *currentLogFilename;
int currentLogRotationAge;
pg_time_t now;
+ WaitEventSet *wes;
now = MyStartTime;
@@ -298,6 +299,22 @@ SysLoggerMain(int argc, char *argv[])
*/
whereToSendOutput = DestNone;
+ /*
+ * Set up a reusable WaitEventSet object we'll use to wait for our latch,
+ * and (except on Windows) our socket.
+ *
+ * Unlike all other postmaster child processes, we'll ignore postmaster
+ * death because we want to collect final log output from all backends and
+ * then exit last. We'll do that by running until we see EOF on the
+ * syslog pipe, which implies that all other backends have exited
+ * (including the postmaster).
+ */
+ wes = CreateWaitEventSet(CurrentMemoryContext, 2);
+ AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL);
+#ifndef WIN32
+ AddWaitEventToSet(wes, WL_SOCKET_READABLE, syslogPipe[0], NULL, NULL);
+#endif
+
/* main worker loop */
for (;;)
{
@@ -305,6 +322,7 @@ SysLoggerMain(int argc, char *argv[])
int size_rotation_for = 0;
long cur_timeout;
int cur_flags;
+ WaitEvent event;
#ifndef WIN32
int rc;
@@ -452,13 +470,10 @@ SysLoggerMain(int argc, char *argv[])
* Sleep until there's something to do
*/
#ifndef WIN32
- rc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
- syslogPipe[0],
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ rc = WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
- if (rc & WL_SOCKET_READABLE)
+ if (rc == 1 && event.events == WL_SOCKET_READABLE)
{
int bytesRead;
@@ -505,10 +520,8 @@ SysLoggerMain(int argc, char *argv[])
*/
LeaveCriticalSection(&sysloggerSection);
- (void) WaitLatch(MyLatch,
- WL_LATCH_SET | cur_flags,
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ (void) WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
EnterCriticalSection(&sysloggerSection);
#endif /* WIN32 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index fb66bceeedf..f0e59dca7d1 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -227,7 +227,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -280,17 +279,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 3f1eae38a92..4b671327fd8 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1686,7 +1686,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 1e1695ef4f4..310bf04d371 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
- WL_LATCH_SET | io_flag,
+ WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,12 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index ada16adb67b..4833ff9d48c 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -221,13 +221,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -498,13 +494,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -546,13 +538,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -1072,14 +1060,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index acc6498567d..159234ef3c7 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,10 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 2054abe6532..41097647443 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1257,14 +1257,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
rc = WaitLatchOrSocket(MyLatch,
WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index 75d26817192..7fc784f5916 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgement, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 6f4b3538ac4..31c5de6f6ac 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -507,7 +507,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -528,15 +528,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -677,13 +668,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -710,7 +694,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 3e51cf3d312..95f30476071 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1216,7 +1216,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1224,13 +1224,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1310,13 +1303,6 @@ WalSndWaitForWal(XLogRecPtr loc)
{
long sleeptime;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1408,8 +1394,8 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
+ WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2124,13 +2110,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
*/
for (;;)
{
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2220,8 +2199,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH | WL_TIMEOUT |
+ WL_SOCKET_READABLE;
/*
* Use fresh timestamp, not last_processed, to reduce the chance
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index f6dda9cc9ac..7a76493269a 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -92,6 +92,13 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * WL_EXIT_ON_PM_DEATH is converted to WL_POSTMASTER_DEATH, but this flag
+ * is set so that we'll exit immediately if postmaster death is detected,
+ * instead of returning.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -370,10 +377,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
(Latch *) latch, NULL);
+ /* Postmaster-managed callers must handle postmaster death somehow. */
+ Assert(!IsUnderPostmaster ||
+ (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
+ (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
+
if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
NULL, NULL);
+ if (wakeEvents & WL_EXIT_ON_PM_DEATH && IsUnderPostmaster)
+ AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+ NULL, NULL);
+
if (wakeEvents & WL_SOCKET_MASK)
{
int ev;
@@ -562,6 +578,7 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->latch = NULL;
set->nevents_space = nevents;
+ set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
#ifdef EPOLL_CLOEXEC
@@ -646,6 +663,7 @@ FreeWaitEventSet(WaitEventSet *set)
* - WL_SOCKET_CONNECTED: Wait for socket connection to be established,
* can be combined with other WL_SOCKET_* events (on non-Windows
* platforms, this is the same as WL_SOCKET_WRITEABLE)
+ * - WL_EXIT_ON_PM_DEATH: Exit immediately if the postmaster dies
*
* Returns the offset in WaitEventSet->events (starting from 0), which can be
* used to modify previously added wait events using ModifyWaitEvent().
@@ -671,6 +689,12 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ if (events == WL_EXIT_ON_PM_DEATH)
+ {
+ events = WL_POSTMASTER_DEATH;
+ set->exit_on_postmaster_death = true;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +950,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -986,7 +1011,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1021,6 +1045,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller asked for
+ * automatic exit in that case.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index fde71afd479..0b9ecf81451 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -949,7 +949,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_SEND);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1093,7 +1094,8 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_RECEIVE);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1181,7 +1183,8 @@ shm_mq_wait_internal(shm_mq *mq, PGPROC **ptr, BackgroundWorkerHandle *handle)
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_INTERNAL);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..851c09ce7ad 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,7 +72,7 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+ AddWaitEventToSet(new_event_set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
@@ -156,15 +156,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6f9aaa52faf..a9c6fd9383c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1263,7 +1263,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
@@ -1776,7 +1776,7 @@ CheckDeadLockAlert(void)
void
ProcWaitForSignal(uint32 wait_event_info)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, wait_event_info);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index b24dece23f8..81c72d8bf80 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -573,7 +573,7 @@ pg_sleep(PG_FUNCTION_ARGS)
break;
(void) WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_ms,
WAIT_EVENT_PG_SLEEP);
ResetLatch(MyLatch);
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index fd8735b7f5f..039a82e1a3a 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -126,8 +126,9 @@ typedef struct Latch
#define WL_SOCKET_WRITEABLE (1 << 2)
#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */
#define WL_POSTMASTER_DEATH (1 << 4)
+#define WL_EXIT_ON_PM_DEATH (1 << 5)
#ifdef WIN32
-#define WL_SOCKET_CONNECTED (1 << 5)
+#define WL_SOCKET_CONNECTED (1 << 6)
#else
/* avoid having to deal with case on platforms not requiring it */
#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 97e8617b3e9..af88110885d 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -280,7 +280,8 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index ebab9866017..b9621c294d1 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -231,7 +231,8 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..52a3208527e 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.17.0
At Sun, 2 Sep 2018 07:04:19 +1200, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=0=PkSXQ5oNU8BhY1DEzxw_EspsU14D_zAPnj+fBAjxFQ@mail.gmail.com>
# Is it intentional that the patch doesn't touch pgstat.c?
Yes. pgstat.c still uses WL_POSTMASTER_DEATH because it does
something special: it calls pgstat_write_statsfiles() before it exits.
Mmm. Exactly..
Rebased.
Thank you for the new version.
===
In sysloger.c, cur_flags is (just set but) no longer used.
===
In latch.c,
- The parentheses around the symbols don't seem to be needed.
| (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
| (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
- The following assertion looks contradicting to the comment.
| /* Postmaster-managed callers must handle postmaster death somehow. */
| Assert(!IsUnderPostmaster ||
| (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
| (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
(Maybe Assert(IsUnderPost && (wakeEv & (WL_EXI | WL_PO)) != 0);)
And don't we need a description about this restriction in the
function comment?
- I think it may be better that the followings had parentheses
around '&' expressions.
| if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
| if (wakeEvents & WL_EXIT_ON_PM_DEATH && IsUnderPostmaster)
===
All the caller sites of WaitLatch, WaitLatchOrSocket and
WaitEventSetWait are covered by this patch and all them look
fine.
bgworker.c, pgstat.c, be-secure-openssl.c, be-secure.c:
Not modified on purpose. WL_EXIT_POSTMASTER_DEATH is not proper
to use there.
pgarch.c, syncrep.c, walsender.c:
Removed redundant check of postmaster death.
syslogger.c:
Left as it doesn't exit at postmaster death on purpose. Uses
reusable wait event set.
walrceiver.c:
Adds new bailing out point in WalRcvWaitForStartPosition and it
seems reasonable.
shm_mq.c:
Adds PMdie bail out in shm_mq_send/receive_bytes, wait_internal.
It looks fine.
postgres_fdw/connection.c:
Adds pm_die bailout while getting result. This seems to be a bug fix.
I'm fine with it included in this patch.
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
Ugrrr! PLEASE ignore this! It's not wrong at all.
2018年9月6日(木) 18:58 Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>:
- The following assertion looks contradicting to the comment.
| /* Postmaster-managed callers must handle postmaster death somehow. */
| Assert(!IsUnderPostmaster ||
| (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
| (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
--
Kyotaro Horiguchi
NTT Open Source Software Center
On Thu, Sep 6, 2018 at 9:57 PM Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
In sysloger.c, cur_flags is (just set but) no longer used.
Right. Fixed.
===
In latch.c,- The parentheses around the symbols don't seem to be needed.
| (wakeEvents & (WL_EXIT_ON_PM_DEATH)) != 0 ||
| (wakeEvents & (WL_POSTMASTER_DEATH)) != 0);
Fixed.
And don't we need a description about this restriction in the
function comment?
Ok, added.
- I think it may be better that the followings had parentheses
around '&' expressions.| if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
| if (wakeEvents & WL_EXIT_ON_PM_DEATH && IsUnderPostmaster)
Fixed. Also I was a little inconsistent about whether to use implicit
or explicit comparison with 0, and decided to go for the former.
All the caller sites of WaitLatch, WaitLatchOrSocket and
WaitEventSetWait are covered by this patch and all them look
fine.
Thanks for the review!
While rebasing, I also changed WL_EXIT_ON_PM_DEATH's means of exit
from exit(1) to proc_exit(1). In master we're quite inconsistent
about that as you can see from the lines removed by this patch, but
the comments for proc_exit() seem to insist that it is the one true
way out. Other than an elog(DEBUG3) message, the main difference
between proc_exit() and direct exit() seems to be the PROFILE_PID_DIR
stuff that changes directory on the way out the door for gprof users.
It looks like per-pid gmon files could have been achieved by setting
environment variables[1]https://sourceware.org/git/?p=glibc.git;a=blob;f=gmon/gmon.c;hb=HEAD#l354[2]https://github.com/freebsd/freebsd/blob/master/lib/libc/gmon/gmon.c#L154, but I guess there is some value in doing
it the same way on every platform.
[1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=gmon/gmon.c;hb=HEAD#l354
[2]: https://github.com/freebsd/freebsd/blob/master/lib/libc/gmon/gmon.c#L154
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v4.patchapplication/octet-stream; name=0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v4.patchDownload
From ca821798c2fb09164a7bf89ced267e94c2ba46bf Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll().
Author: Thomas Munro
Reviewed-by: Kyotaro Horiguchi, Heikki Linnakangas
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
- | 0
contrib/pg_prewarm/autoprewarm.c | 6 +--
contrib/postgres_fdw/connection.c | 6 ++-
src/backend/access/transam/parallel.c | 8 +---
src/backend/access/transam/xlog.c | 6 +--
src/backend/executor/nodeGather.c | 3 +-
src/backend/libpq/pqmq.c | 2 +-
src/backend/postmaster/autovacuum.c | 16 ++-----
src/backend/postmaster/bgwriter.c | 11 +----
src/backend/postmaster/checkpointer.c | 16 ++-----
src/backend/postmaster/pgarch.c | 4 +-
src/backend/postmaster/syslogger.c | 38 +++++++++------
src/backend/postmaster/walwriter.c | 16 ++-----
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 13 +----
src/backend/replication/logical/launcher.c | 24 ++--------
src/backend/replication/logical/tablesync.c | 30 ++++--------
src/backend/replication/logical/worker.c | 6 +--
src/backend/replication/syncrep.c | 18 +++----
src/backend/replication/walreceiver.c | 20 +-------
src/backend/replication/walsender.c | 31 ++----------
src/backend/storage/ipc/latch.c | 47 ++++++++++++++++++-
src/backend/storage/ipc/shm_mq.c | 9 ++--
src/backend/storage/lmgr/condition_variable.c | 11 +----
src/backend/storage/lmgr/proc.c | 4 +-
src/backend/utils/adt/misc.c | 2 +-
src/include/storage/latch.h | 3 +-
src/test/modules/test_shm_mq/setup.c | 3 +-
src/test/modules/test_shm_mq/test.c | 3 +-
src/test/modules/worker_spi/worker_spi.c | 6 +--
30 files changed, 149 insertions(+), 215 deletions(-)
create mode 100644 -
diff --git a/- b/-
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index 03bf90ce2d8..7169ac3cc7f 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -220,7 +220,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
}
@@ -249,15 +249,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
/* Reset the latch, bail out if postmaster died, otherwise loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index fe4893a8e05..a6509932dcf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -546,7 +546,8 @@ pgfdw_get_result(PGconn *conn, const char *query)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
-1L, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
@@ -1152,7 +1153,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
cur_timeout, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 84197192ec2..dc172d5480c 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -692,13 +692,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -815,7 +811,7 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
}
}
- WaitLatch(MyLatch, WL_LATCH_SET, -1,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
WAIT_EVENT_PARALLEL_FINISH);
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7375a78ffcf..c5ffb35778f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6210,7 +6210,7 @@ recoveryApplyDelay(XLogReaderState *record)
secs, microsecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
secs * 1000L + microsecs / 1000,
WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
@@ -12127,7 +12127,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
(secs * 1000 + usecs / 1000);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
@@ -12303,7 +12303,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* to react to a trigger file promptly.
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index ad16c783bd8..a6b90227335 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -362,7 +362,8 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_EXECUTE_GATHER);
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 6eaed5bf0cf..0a15d32e4a5 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,7 +168,7 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_MQ_PUT_MESSAGE);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 978089575b8..2d7c65b7cbb 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -628,7 +628,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -644,23 +643,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index b1e9bb2c537..3da7bdac1de 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -339,7 +339,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -366,20 +366,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 1a033093c53..8c2cdda3f5a 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -344,7 +344,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -545,17 +544,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 29bdcec8958..d4600f485ea 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -168,6 +168,7 @@ SysLoggerMain(int argc, char *argv[])
char *currentLogFilename;
int currentLogRotationAge;
pg_time_t now;
+ WaitEventSet *wes;
now = MyStartTime;
@@ -298,13 +299,29 @@ SysLoggerMain(int argc, char *argv[])
*/
whereToSendOutput = DestNone;
+ /*
+ * Set up a reusable WaitEventSet object we'll use to wait for our latch,
+ * and (except on Windows) our socket.
+ *
+ * Unlike all other postmaster child processes, we'll ignore postmaster
+ * death because we want to collect final log output from all backends and
+ * then exit last. We'll do that by running until we see EOF on the
+ * syslog pipe, which implies that all other backends have exited
+ * (including the postmaster).
+ */
+ wes = CreateWaitEventSet(CurrentMemoryContext, 2);
+ AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL);
+#ifndef WIN32
+ AddWaitEventToSet(wes, WL_SOCKET_READABLE, syslogPipe[0], NULL, NULL);
+#endif
+
/* main worker loop */
for (;;)
{
bool time_based_rotation = false;
int size_rotation_for = 0;
long cur_timeout;
- int cur_flags;
+ WaitEvent event;
#ifndef WIN32
int rc;
@@ -440,25 +457,18 @@ SysLoggerMain(int argc, char *argv[])
}
else
cur_timeout = 0;
- cur_flags = WL_TIMEOUT;
}
else
- {
cur_timeout = -1L;
- cur_flags = 0;
- }
/*
* Sleep until there's something to do
*/
#ifndef WIN32
- rc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
- syslogPipe[0],
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ rc = WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
- if (rc & WL_SOCKET_READABLE)
+ if (rc == 1 && event.events == WL_SOCKET_READABLE)
{
int bytesRead;
@@ -505,10 +515,8 @@ SysLoggerMain(int argc, char *argv[])
*/
LeaveCriticalSection(&sysloggerSection);
- (void) WaitLatch(MyLatch,
- WL_LATCH_SET | cur_flags,
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ (void) WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
EnterCriticalSection(&sysloggerSection);
#endif /* WIN32 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index fb66bceeedf..f0e59dca7d1 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -227,7 +227,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -280,17 +279,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b20f6c379c6..a7e3db27832 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1686,7 +1686,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 1e1695ef4f4..310bf04d371 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
- WL_LATCH_SET | io_flag,
+ WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,12 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index ada16adb67b..4833ff9d48c 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -221,13 +221,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -498,13 +494,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -546,13 +538,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -1072,14 +1060,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 6e420d893cf..e4451febc2e 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,10 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 277da69fa6c..79fbf07a737 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1258,14 +1258,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
rc = WaitLatchOrSocket(MyLatch,
WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index af5ad5fe66f..9a13c50ce88 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgment, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 6f4b3538ac4..31c5de6f6ac 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -507,7 +507,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -528,15 +528,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -677,13 +668,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -710,7 +694,7 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ WaitLatch(walrcv->latch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 2683385ca6e..8204196d26b 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1218,7 +1218,7 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
@@ -1226,13 +1226,6 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
MyProcPort->sock, sleeptime,
WAIT_EVENT_WAL_SENDER_WRITE_DATA);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1312,13 +1305,6 @@ WalSndWaitForWal(XLogRecPtr loc)
{
long sleeptime;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1410,8 +1396,8 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
+ WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
@@ -2126,13 +2112,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
*/
for (;;)
{
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2222,8 +2201,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH | WL_TIMEOUT |
+ WL_SOCKET_READABLE;
/*
* Use fresh timestamp, not last_processed, to reduce the chance
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index f6dda9cc9ac..312da02394d 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -48,6 +48,7 @@
#include "port/atomics.h"
#include "portability/instr_time.h"
#include "postmaster/postmaster.h"
+#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/shmem.h"
@@ -92,6 +93,13 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * WL_EXIT_ON_PM_DEATH is converted to WL_POSTMASTER_DEATH, but this flag
+ * is set so that we'll exit immediately if postmaster death is detected,
+ * instead of returning.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -348,6 +356,11 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
* to be reported as readable/writable/connected, so that the caller can deal
* with the condition.
*
+ * wakeEvents must include either WL_EXIT_ON_PM_DEATH for automatic exit
+ * if the postmaster dies or WL_POSTMASTER_DEATH for a flag set in the
+ * return value if the postmaster dies. The latter is useful for rare cases
+ * where some behavior other than immediate exit is needed.
+ *
* NB: These days this is just a wrapper around the WaitEventSet API. When
* using a latch very frequently, consider creating a longer living
* WaitEventSet instead; that's more efficient.
@@ -370,10 +383,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
(Latch *) latch, NULL);
- if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
+ /* Postmaster-managed callers must handle postmaster death somehow. */
+ Assert(!IsUnderPostmaster ||
+ (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
+ (wakeEvents & WL_POSTMASTER_DEATH));
+
+ if ((wakeEvents & WL_POSTMASTER_DEATH) && IsUnderPostmaster)
AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
NULL, NULL);
+ if ((wakeEvents & WL_EXIT_ON_PM_DEATH) && IsUnderPostmaster)
+ AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+ NULL, NULL);
+
if (wakeEvents & WL_SOCKET_MASK)
{
int ev;
@@ -562,6 +584,7 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->latch = NULL;
set->nevents_space = nevents;
+ set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
#ifdef EPOLL_CLOEXEC
@@ -646,6 +669,7 @@ FreeWaitEventSet(WaitEventSet *set)
* - WL_SOCKET_CONNECTED: Wait for socket connection to be established,
* can be combined with other WL_SOCKET_* events (on non-Windows
* platforms, this is the same as WL_SOCKET_WRITEABLE)
+ * - WL_EXIT_ON_PM_DEATH: Exit immediately if the postmaster dies
*
* Returns the offset in WaitEventSet->events (starting from 0), which can be
* used to modify previously added wait events using ModifyWaitEvent().
@@ -671,6 +695,12 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ if (events == WL_EXIT_ON_PM_DEATH)
+ {
+ events = WL_POSTMASTER_DEATH;
+ set->exit_on_postmaster_death = true;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -926,6 +956,7 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
instr_time start_time;
instr_time cur_time;
long cur_timeout = -1;
+ int i;
Assert(nevents > 0);
@@ -986,7 +1017,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1021,6 +1051,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller asked for
+ * automatic exit in that case.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ proc_exit(1);
+ }
+ }
+
return returned_events;
}
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index fde71afd479..0b9ecf81451 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -949,7 +949,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_SEND);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1093,7 +1094,8 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_RECEIVE);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1181,7 +1183,8 @@ shm_mq_wait_internal(shm_mq *mq, PGPROC **ptr, BackgroundWorkerHandle *handle)
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_INTERNAL);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..851c09ce7ad 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,7 +72,7 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+ AddWaitEventToSet(new_event_set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
@@ -156,15 +156,6 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
*/
WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
-
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6f9aaa52faf..a9c6fd9383c 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1263,7 +1263,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
@@ -1776,7 +1776,7 @@ CheckDeadLockAlert(void)
void
ProcWaitForSignal(uint32 wait_event_info)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0, wait_event_info);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 6ea3679835b..8fab722b98f 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -379,7 +379,7 @@ pg_sleep(PG_FUNCTION_ARGS)
break;
(void) WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_ms,
WAIT_EVENT_PG_SLEEP);
ResetLatch(MyLatch);
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index fd8735b7f5f..039a82e1a3a 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -126,8 +126,9 @@ typedef struct Latch
#define WL_SOCKET_WRITEABLE (1 << 2)
#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */
#define WL_POSTMASTER_DEATH (1 << 4)
+#define WL_EXIT_ON_PM_DEATH (1 << 5)
#ifdef WIN32
-#define WL_SOCKET_CONNECTED (1 << 5)
+#define WL_SOCKET_CONNECTED (1 << 6)
#else
/* avoid having to deal with case on platforms not requiring it */
#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 97e8617b3e9..af88110885d 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -280,7 +280,8 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index ebab9866017..b9621c294d1 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -231,7 +231,8 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..52a3208527e 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.19.1
Thank you for the fix.
At Tue, 23 Oct 2018 17:26:37 +1300, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=3BxOHw63Anwyx=pyy7Ju8cW6T0ZXNeKQS=WZp80hv_rg@mail.gmail.com>
On Thu, Sep 6, 2018 at 9:57 PM Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:And don't we need a description about this restriction in the
function comment?Ok, added.
Thank you. It looks good.
While rebasing, I also changed WL_EXIT_ON_PM_DEATH's means of exit
from exit(1) to proc_exit(1). In master we're quite inconsistent
about that as you can see from the lines removed by this patch, but
the comments for proc_exit() seem to insist that it is the one true
way out. Other than an elog(DEBUG3) message, the main difference
between proc_exit() and direct exit() seems to be the PROFILE_PID_DIR
stuff that changes directory on the way out the door for gprof users.
It looks exactly like that for me, too.
It looks like per-pid gmon files could have been achieved by setting
environment variables[1][2], but I guess there is some value in doing
it the same way on every platform.[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=gmon/gmon.c;hb=HEAD#l354
[2] https://github.com/freebsd/freebsd/blob/master/lib/libc/gmon/gmon.c#L154
Agreed. Anyway they don't allow the tweak for avworker.
It seems fine for me. I'm going to mark this ReadyForCommitter
after a few days of waiting for anyone who has more
comments/opinions.
https://commitfest.postgresql.org/20/1618/
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
At Fri, 26 Oct 2018 14:13:51 +0900 (Tokyo Standard Time), Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp> wrote in <20181026.141351.09076928.horiguchi.kyotaro@lab.ntt.co.jp>
Thank you for the fix.
At Tue, 23 Oct 2018 17:26:37 +1300, Thomas Munro <thomas.munro@enterprisedb.com> wrote in <CAEepm=3BxOHw63Anwyx=pyy7Ju8cW6T0ZXNeKQS=WZp80hv_rg@mail.gmail.com>
On Thu, Sep 6, 2018 at 9:57 PM Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:And don't we need a description about this restriction in the
function comment?Ok, added.
Thank you. It looks good.
While rebasing, I also changed WL_EXIT_ON_PM_DEATH's means of exit
from exit(1) to proc_exit(1). In master we're quite inconsistent
about that as you can see from the lines removed by this patch, but
the comments for proc_exit() seem to insist that it is the one true
way out. Other than an elog(DEBUG3) message, the main difference
between proc_exit() and direct exit() seems to be the PROFILE_PID_DIR
stuff that changes directory on the way out the door for gprof users.It looks exactly like that for me, too.
It looks like per-pid gmon files could have been achieved by setting
environment variables[1][2], but I guess there is some value in doing
it the same way on every platform.[1] https://sourceware.org/git/?p=glibc.git;a=blob;f=gmon/gmon.c;hb=HEAD#l354
[2] https://github.com/freebsd/freebsd/blob/master/lib/libc/gmon/gmon.c#L154Agreed. Anyway they don't allow the tweak for avworker.
It seems fine for me. I'm going to mark this ReadyForCommitter
after a few days of waiting for anyone who has more
comments/opinions.
Seen no objection nor further comments. I marked this as "Ready
for Committer".
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
Thomas Munro <thomas.munro@enterprisedb.com> writes:
[ 0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v4.patch ]
I took a quick look through this. I have no objection to the idea of
letting the latch infrastructure do the proc_exit(1), but I'm wondering
why this is in the thread that it's in. Is there any remaining connection
to the original complaint about BSDen not coping well with lots of
processes waiting on the same pipe?
A couple minor code gripes:
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
I'd advise making the code in places like this look like
(void) WaitLatch(MyLatch, ...);
Otherwise, you are likely to draw complaints about "return value is
sometimes ignored" from Coverity and other static analyzers. The
(void) cast makes it explicit that you're intentionally ignoring
the result value in this one place.
@@ -1021,6 +1051,19 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
pgstat_report_wait_end();
+ /*
+ * Exit immediately if the postmaster died and the caller asked for
+ * automatic exit in that case.
+ */
+ if (set->exit_on_postmaster_death)
+ {
+ for (i = 0; i < returned_events; ++i)
+ {
+ if (occurred_events[i].events == WL_POSTMASTER_DEATH)
+ proc_exit(1);
+ }
+ }
+
return returned_events;
}
Since exit_on_postmaster_death = true is going to be the normal case,
it seems a bit unfortunate that we have to incur this looping every time
we go through WaitEventSetWait. Can't we put the handling of this in some
spot where it only gets executed when we've detected WL_POSTMASTER_DEATH,
like right after the PostmasterIsAliveInternal calls?
if (!PostmasterIsAliveInternal())
{
+ if (set->exit_on_postmaster_death)
+ proc_exit(1);
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
occurred_events++;
returned_events++;
}
regards, tom lane
On Sat, Nov 17, 2018 at 5:56 AM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Thomas Munro <thomas.munro@enterprisedb.com> writes:
[ 0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v4.patch ]
I took a quick look through this. I have no objection to the idea of
letting the latch infrastructure do the proc_exit(1), but I'm wondering
why this is in the thread that it's in. Is there any remaining connection
to the original complaint about BSDen not coping well with lots of
processes waiting on the same pipe?
It turned into a general clean-up of inconsistent postmaster death
handling after the one-pipe-per-backend proposal was rejected.
Perhaps I should have started a new thread, but it does in fact
address most cases of processes calling PostmasterIsAlive()
frequently, which was part of the original complaint. That falls into
the last-mentioned category from this paragraph of the commit message:
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Other potential improvements that could be made on both sides:
* We should probably be smarter about how often we call
PostmasterIsAlive() in the recovery loop, which is the only remaining
case like that (because it's a busy loop, given enough WAL to chew on,
so there is no waiting primitive that would report pipe readiness).
* It would be nice if more kernels supported parent death signals.
* Based on this report, those kernels really should sort out their
wakeup logic for duplicated pipe fds. I wonder if other multi-process
applications have the same problem. Our logger pipe and the proposed
checkpointer fsync pipe too, maybe, not sure.
I'd advise making the code in places like this look like
(void) WaitLatch(MyLatch, ...);
Otherwise, you are likely to draw complaints about "return value is
sometimes ignored" from Coverity and other static analyzers. The
(void) cast makes it explicit that you're intentionally ignoring
the result value in this one place.
Done.
Since exit_on_postmaster_death = true is going to be the normal case,
it seems a bit unfortunate that we have to incur this looping every time
we go through WaitEventSetWait. Can't we put the handling of this in some
spot where it only gets executed when we've detected WL_POSTMASTER_DEATH,
like right after the PostmasterIsAliveInternal calls?if (!PostmasterIsAliveInternal()) { + if (set->exit_on_postmaster_death) + proc_exit(1); occurred_events->fd = PGINVALID_SOCKET; occurred_events->events = WL_POSTMASTER_DEATH; occurred_events++; returned_events++; }
I was probably trying to avoid repeating the code in each of the 3
implementations of that function (poll, epoll, win32). But there is
already other similar duplication there and I agree that is better.
Done that way.
Thanks for the review.
--
Thomas Munro
http://www.enterprisedb.com
Attachments:
0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v5.patchapplication/octet-stream; name=0001-Add-WL_EXIT_ON_PM_DEATH-pseudo-event-v5.patchDownload
From 3fe553a3654b3eae564423d381a7f9e9a0e48db9 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
Date: Wed, 11 Apr 2018 11:30:36 +1200
Subject: [PATCH] Add WL_EXIT_ON_PM_DEATH pseudo-event.
Users of the WaitEventSet and WaitLatch() APIs can now choose between
asking for WL_POSTMASTER_DEATH and then handling it explicitly, or asking
for WL_EXIT_ON_PM_DEATH to trigger immediate exit on postmaster death.
This reduces code duplication, since almost all callers want the latter.
Repair all code that was previously ignoring postmaster death completely,
or requesting the event but ignoring it, or requesting the event but then
doing an unconditional PostmasterIsAlive() call every time through its
event loop (which is an expensive syscall on platforms for which we don't
have USE_POSTMASTER_DEATH_SIGNAL support).
Assert that callers of WaitLatchXXX() under the postmaster remember to
ask for either WL_POSTMASTER_DEATH or WL_EXIT_ON_PM_DEATH, to prevent
future bugs.
The only process that doesn't handle postmaster death is syslogger. It
waits until all backends holding the write end of the syslog pipe
(including the postmaster) have closed it by exiting, to be sure to
capture any parting messages. By using the WaitEventSet API directly
it avoids the new assertion, and as a by-product it may be slightly
more efficient on platforms that have epoll(). (Thanks to Andres Freund
for pointing out the value of that special case.)
Author: Thomas Munro
Reviewed-by: Kyotaro Horiguchi, Heikki Linnakangas, Tom Lane
Discussion: https://postgr.es/m/CAEepm%3D1TCviRykkUb69ppWLr_V697rzd1j3eZsRMmbXvETfqbQ%40mail.gmail.com,
https://postgr.es/m/CAEepm=2LqHzizbe7muD7-2yHUbTOoF7Q+qkSD5Q41kuhttRTwA@mail.gmail.com
---
- | 0
contrib/pg_prewarm/autoprewarm.c | 8 ++-
contrib/postgres_fdw/connection.c | 6 ++-
src/backend/access/transam/parallel.c | 10 ++--
src/backend/access/transam/xlog.c | 23 +++++----
src/backend/access/transam/xlogfuncs.c | 8 +--
src/backend/executor/nodeGather.c | 3 +-
src/backend/libpq/be-secure-openssl.c | 4 +-
src/backend/libpq/pqmq.c | 4 +-
src/backend/postmaster/autovacuum.c | 16 ++----
src/backend/postmaster/bgwriter.c | 11 +----
src/backend/postmaster/checkpointer.c | 16 ++----
src/backend/postmaster/pgarch.c | 4 +-
src/backend/postmaster/syslogger.c | 38 ++++++++------
src/backend/postmaster/walwriter.c | 16 ++----
src/backend/replication/basebackup.c | 2 +-
.../libpqwalreceiver/libpqwalreceiver.c | 13 +----
src/backend/replication/logical/launcher.c | 24 ++-------
src/backend/replication/logical/tablesync.c | 30 +++---------
src/backend/replication/logical/worker.c | 6 +--
src/backend/replication/syncrep.c | 18 ++++---
src/backend/replication/walreceiver.c | 22 ++-------
src/backend/replication/walsender.c | 49 ++++++-------------
src/backend/storage/ipc/latch.c | 39 ++++++++++++++-
src/backend/storage/ipc/shm_mq.c | 9 ++--
src/backend/storage/lmgr/condition_variable.c | 14 ++----
src/backend/storage/lmgr/proc.c | 7 +--
src/backend/utils/adt/misc.c | 2 +-
src/include/storage/latch.h | 3 +-
src/test/modules/test_shm_mq/setup.c | 3 +-
src/test/modules/test_shm_mq/test.c | 3 +-
src/test/modules/worker_spi/worker_spi.c | 6 +--
32 files changed, 174 insertions(+), 243 deletions(-)
create mode 100644 -
diff --git a/- b/-
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index 03bf90ce2d8..c2a6e5a53f7 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -220,7 +220,7 @@ autoprewarm_main(Datum main_arg)
{
/* We're only dumping at shutdown, so just wait forever. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1L,
PG_WAIT_EXTENSION);
}
@@ -249,15 +249,13 @@ autoprewarm_main(Datum main_arg)
/* Sleep until the next dump time. */
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_in_ms,
PG_WAIT_EXTENSION);
}
- /* Reset the latch, bail out if postmaster died, otherwise loop. */
+ /* Reset the latch, loop. */
ResetLatch(&MyProc->procLatch);
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
}
/*
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index fe4893a8e05..a6509932dcf 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -546,7 +546,8 @@ pgfdw_get_result(PGconn *conn, const char *query)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
-1L, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
@@ -1152,7 +1153,8 @@ pgfdw_get_cleanup_result(PGconn *conn, TimestampTz endtime, PGresult **result)
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | WL_TIMEOUT,
+ WL_LATCH_SET | WL_SOCKET_READABLE |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
PQsocket(conn),
cur_timeout, PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 84197192ec2..b9a9ae5c73c 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -692,13 +692,9 @@ WaitForParallelWorkersToAttach(ParallelContext *pcxt)
* just end up waiting for the same worker again.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
-1, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -815,8 +811,8 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
}
}
- WaitLatch(MyLatch, WL_LATCH_SET, -1,
- WAIT_EVENT_PARALLEL_FINISH);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
+ WAIT_EVENT_PARALLEL_FINISH);
ResetLatch(MyLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7eed5866d2e..b5bb37128a8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6192,10 +6192,10 @@ recoveryApplyDelay(XLogReaderState *record)
elog(DEBUG2, "recovery apply delay %ld seconds, %d milliseconds",
secs, microsecs / 1000);
- WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- secs * 1000L + microsecs / 1000,
- WAIT_EVENT_RECOVERY_APPLY_DELAY);
+ (void) WaitLatch(&XLogCtl->recoveryWakeupLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ secs * 1000L + microsecs / 1000,
+ WAIT_EVENT_RECOVERY_APPLY_DELAY);
}
return true;
}
@@ -12096,9 +12096,11 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
wait_time = wal_retrieve_retry_interval -
(secs * 1000 + usecs / 1000);
- WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- wait_time, WAIT_EVENT_RECOVERY_WAL_STREAM);
+ (void) WaitLatch(&XLogCtl->recoveryWakeupLatch,
+ WL_LATCH_SET | WL_TIMEOUT |
+ WL_EXIT_ON_PM_DEATH,
+ wait_time,
+ WAIT_EVENT_RECOVERY_WAL_STREAM);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
}
@@ -12272,9 +12274,10 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* Wait for more WAL to arrive. Time out after 5 seconds
* to react to a trigger file promptly.
*/
- WaitLatch(&XLogCtl->recoveryWakeupLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
+ (void) WaitLatch(&XLogCtl->recoveryWakeupLatch,
+ WL_LATCH_SET | WL_TIMEOUT |
+ WL_EXIT_ON_PM_DEATH,
+ 5000L, WAIT_EVENT_RECOVERY_WAL_ALL);
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
}
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index a31adcca5eb..be0799ccff3 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -764,10 +764,10 @@ pg_promote(PG_FUNCTION_ARGS)
CHECK_FOR_INTERRUPTS();
- WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L / WAITS_PER_SECOND,
- WAIT_EVENT_PROMOTE);
+ (void) WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ 1000L / WAITS_PER_SECOND,
+ WAIT_EVENT_PROMOTE);
}
ereport(WARNING,
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index c979a557749..e6367ade76d 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -383,7 +383,8 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_EXECUTE_GATHER);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_EXECUTE_GATHER);
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 6a576572bbe..c5ae87f0673 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -398,8 +398,8 @@ aloop:
else
waitfor = WL_SOCKET_WRITEABLE;
- WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0,
- WAIT_EVENT_SSL_OPEN_SERVER);
+ (void) WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0,
+ WAIT_EVENT_SSL_OPEN_SERVER);
goto aloop;
case SSL_ERROR_SYSCALL:
if (r < 0)
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 6eaed5bf0cf..603d9016fd8 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,8 +168,8 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
- WAIT_EVENT_MQ_PUT_MESSAGE);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_PUT_MESSAGE);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 978089575b8..5d46043bc57 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -628,7 +628,6 @@ AutoVacLauncherMain(int argc, char *argv[])
struct timeval nap;
TimestampTz current_time = 0;
bool can_launch;
- int rc;
/*
* This loop is a bit different from the normal use of WaitLatch,
@@ -644,23 +643,16 @@ AutoVacLauncherMain(int argc, char *argv[])
* Wait until naptime expires or we get some type of signal (all the
* signal handlers will wake us by calling SetLatch).
*/
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
- WAIT_EVENT_AUTOVACUUM_MAIN);
+ (void) WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ WAIT_EVENT_AUTOVACUUM_MAIN);
ResetLatch(MyLatch);
/* Process sinval catchup interrupts that happened while sleeping */
ProcessCatchupInterrupt();
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
/* the normal shutdown case */
if (got_SIGTERM)
break;
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index b1e9bb2c537..3da7bdac1de 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -339,7 +339,7 @@ BackgroundWriterMain(void)
* normal operation.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay /* ms */ , WAIT_EVENT_BGWRITER_MAIN);
/*
@@ -366,20 +366,13 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
BgWriterDelay * HIBERNATE_FACTOR,
WAIT_EVENT_BGWRITER_HIBERNATE);
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
prev_hibernate = can_hibernate;
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 1a033093c53..cfdd98f23f8 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -344,7 +344,6 @@ CheckpointerMain(void)
pg_time_t now;
int elapsed_secs;
int cur_timeout;
- int rc;
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -545,17 +544,10 @@ CheckpointerMain(void)
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ ,
- WAIT_EVENT_CHECKPOINTER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ (void) WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout * 1000L /* convert to ms */ ,
+ WAIT_EVENT_CHECKPOINTER_MAIN);
}
}
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 885e85ad8af..e43ac4d4f47 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -393,6 +393,8 @@ pgarch_MainLoop(void)
WAIT_EVENT_ARCHIVER_MAIN);
if (rc & WL_TIMEOUT)
wakened = true;
+ if (rc & WL_POSTMASTER_DEATH)
+ time_to_stop = true;
}
else
wakened = true;
@@ -403,7 +405,7 @@ pgarch_MainLoop(void)
* or after completing one more archiving cycle after receiving
* SIGUSR2.
*/
- } while (PostmasterIsAlive() && !time_to_stop);
+ } while (!time_to_stop);
}
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 29bdcec8958..d4600f485ea 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -168,6 +168,7 @@ SysLoggerMain(int argc, char *argv[])
char *currentLogFilename;
int currentLogRotationAge;
pg_time_t now;
+ WaitEventSet *wes;
now = MyStartTime;
@@ -298,13 +299,29 @@ SysLoggerMain(int argc, char *argv[])
*/
whereToSendOutput = DestNone;
+ /*
+ * Set up a reusable WaitEventSet object we'll use to wait for our latch,
+ * and (except on Windows) our socket.
+ *
+ * Unlike all other postmaster child processes, we'll ignore postmaster
+ * death because we want to collect final log output from all backends and
+ * then exit last. We'll do that by running until we see EOF on the
+ * syslog pipe, which implies that all other backends have exited
+ * (including the postmaster).
+ */
+ wes = CreateWaitEventSet(CurrentMemoryContext, 2);
+ AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL);
+#ifndef WIN32
+ AddWaitEventToSet(wes, WL_SOCKET_READABLE, syslogPipe[0], NULL, NULL);
+#endif
+
/* main worker loop */
for (;;)
{
bool time_based_rotation = false;
int size_rotation_for = 0;
long cur_timeout;
- int cur_flags;
+ WaitEvent event;
#ifndef WIN32
int rc;
@@ -440,25 +457,18 @@ SysLoggerMain(int argc, char *argv[])
}
else
cur_timeout = 0;
- cur_flags = WL_TIMEOUT;
}
else
- {
cur_timeout = -1L;
- cur_flags = 0;
- }
/*
* Sleep until there's something to do
*/
#ifndef WIN32
- rc = WaitLatchOrSocket(MyLatch,
- WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
- syslogPipe[0],
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ rc = WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
- if (rc & WL_SOCKET_READABLE)
+ if (rc == 1 && event.events == WL_SOCKET_READABLE)
{
int bytesRead;
@@ -505,10 +515,8 @@ SysLoggerMain(int argc, char *argv[])
*/
LeaveCriticalSection(&sysloggerSection);
- (void) WaitLatch(MyLatch,
- WL_LATCH_SET | cur_flags,
- cur_timeout,
- WAIT_EVENT_SYSLOGGER_MAIN);
+ (void) WaitEventSetWait(wes, cur_timeout, &event, 1,
+ WAIT_EVENT_SYSLOGGER_MAIN);
EnterCriticalSection(&sysloggerSection);
#endif /* WIN32 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index fb66bceeedf..ff10ff7c3ae 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -227,7 +227,6 @@ WalWriterMain(void)
for (;;)
{
long cur_timeout;
- int rc;
/*
* Advertise whether we might hibernate in this cycle. We do this
@@ -280,17 +279,10 @@ WalWriterMain(void)
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout,
- WAIT_EVENT_WAL_WRITER_MAIN);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
+ (void) WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ cur_timeout,
+ WAIT_EVENT_WAL_WRITER_MAIN);
}
}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b20f6c379c6..a7e3db27832 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1686,7 +1686,7 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
(long) (sleep / 1000),
WAIT_EVENT_BASE_BACKUP_THROTTLE);
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 1e1695ef4f4..310bf04d371 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -186,16 +186,11 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
io_flag = WL_SOCKET_WRITEABLE;
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH |
- WL_LATCH_SET | io_flag,
+ WL_EXIT_ON_PM_DEATH | WL_LATCH_SET | io_flag,
PQsocket(conn->streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
@@ -610,16 +605,12 @@ libpqrcv_PQexec(PGconn *streamConn, const char *query)
* replication connection.
*/
rc = WaitLatchOrSocket(MyLatch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_LATCH_SET,
PQsocket(streamConn),
0,
WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE);
- /* Emergency bailout? */
- if (rc & WL_POSTMASTER_DEATH)
- exit(1);
-
/* Interrupted? */
if (rc & WL_LATCH_SET)
{
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index ada16adb67b..4833ff9d48c 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -221,13 +221,9 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker,
* about the worker attach. But we don't expect to have to wait long.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -498,13 +494,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_STARTUP);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -546,13 +538,9 @@ logicalrep_worker_stop(Oid subid, Oid relid)
/* Wait a bit --- we don't expect to have to wait long. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
10L, WAIT_EVENT_BGWORKER_SHUTDOWN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
@@ -1072,14 +1060,10 @@ ApplyLauncherMain(Datum main_arg)
/* Wait for more work. */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
wait_time,
WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 9e682331d2f..38ae1b9ab85 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -159,7 +159,6 @@ finish_sync_worker(void)
static bool
wait_for_relation_state_change(Oid relid, char expected_state)
{
- int rc;
char state;
for (;;)
@@ -192,13 +191,9 @@ wait_for_relation_state_change(Oid relid, char expected_state)
if (!worker)
return false;
- rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
-
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ (void) WaitLatch(MyLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ 1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
ResetLatch(MyLatch);
}
@@ -250,13 +245,9 @@ wait_for_worker_state_change(char expected_state)
* but use a timeout in case it dies without sending one.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
1000L, WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
ResetLatch(MyLatch);
}
@@ -593,7 +584,6 @@ copy_read_data(void *outbuf, int minread, int maxread)
while (maxread > 0 && bytesread < minread)
{
pgsocket fd = PGINVALID_SOCKET;
- int rc;
int len;
char *buf = NULL;
@@ -632,14 +622,10 @@ copy_read_data(void *outbuf, int minread, int maxread)
/*
* Wait for more data or latch.
*/
- rc = WaitLatchOrSocket(MyLatch,
- WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
- fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
-
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
+ (void) WaitLatchOrSocket(MyLatch,
+ WL_SOCKET_READABLE | WL_LATCH_SET |
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+ fd, 1000L, WAIT_EVENT_LOGICAL_SYNC_DATA);
ResetLatch(MyLatch);
}
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 3cd1e0d728e..8d5e0946c4b 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -1264,14 +1264,10 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
rc = WaitLatchOrSocket(MyLatch,
WL_SOCKET_READABLE | WL_LATCH_SET |
- WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
fd, wait_time,
WAIT_EVENT_LOGICAL_APPLY_MAIN);
- /* Emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
if (rc & WL_LATCH_SET)
{
ResetLatch(MyLatch);
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index af5ad5fe66f..9a13c50ce88 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -214,6 +214,8 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
*/
for (;;)
{
+ int rc;
+
/* Must reset the latch before testing state. */
ResetLatch(MyLatch);
@@ -266,25 +268,25 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
break;
}
+ /*
+ * Wait on latch. Any condition that should wake us up will set the
+ * latch, so no need for timeout.
+ */
+ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ WAIT_EVENT_SYNC_REP);
+
/*
* If the postmaster dies, we'll probably never get an
* acknowledgment, because all the wal sender processes will exit. So
* just bail out.
*/
- if (!PostmasterIsAlive())
+ if (rc & WL_POSTMASTER_DEATH)
{
ProcDiePending = true;
whereToSendOutput = DestNone;
SyncRepCancelWait();
break;
}
-
- /*
- * Wait on latch. Any condition that should wake us up will set the
- * latch, so no need for timeout.
- */
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
- WAIT_EVENT_SYNC_REP);
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 6f4b3538ac4..166f052bd7c 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -507,7 +507,7 @@ WalReceiverMain(void)
*/
Assert(wait_fd != PGINVALID_SOCKET);
rc = WaitLatchOrSocket(walrcv->latch,
- WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
+ WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
NAPTIME_PER_CYCLE,
@@ -528,15 +528,6 @@ WalReceiverMain(void)
XLogWalRcvSendReply(true, false);
}
}
- if (rc & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to
- * avoid the necessity for manual cleanup of all
- * postmaster children.
- */
- exit(1);
- }
if (rc & WL_TIMEOUT)
{
/*
@@ -677,13 +668,6 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
{
ResetLatch(walrcv->latch);
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
ProcessWalRcvInterrupts();
SpinLockAcquire(&walrcv->mutex);
@@ -710,8 +694,8 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
- WAIT_EVENT_WAL_RECEIVER_WAIT_START);
+ (void) WaitLatch(walrcv->latch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_WAL_RECEIVER_WAIT_START);
}
if (update_process_title)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 39337d2f1f8..75edbe030f5 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1218,20 +1218,13 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
WL_SOCKET_WRITEABLE | WL_SOCKET_READABLE | WL_TIMEOUT;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_WRITE_DATA);
-
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
+ (void) WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_WRITE_DATA);
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1312,13 +1305,6 @@ WalSndWaitForWal(XLogRecPtr loc)
{
long sleeptime;
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -1410,15 +1396,15 @@ WalSndWaitForWal(XLogRecPtr loc)
*/
sleeptime = WalSndComputeSleeptime(GetCurrentTimestamp());
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
- WL_SOCKET_READABLE | WL_TIMEOUT;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH |
+ WL_SOCKET_READABLE | WL_TIMEOUT;
if (pq_is_send_pending())
wakeEvents |= WL_SOCKET_WRITEABLE;
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_WAIT_WAL);
+ (void) WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_WAIT_WAL);
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -2126,13 +2112,6 @@ WalSndLoop(WalSndSendDataCallback send_data)
*/
for (;;)
{
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- if (!PostmasterIsAlive())
- exit(1);
-
/* Clear any already-pending wakeups */
ResetLatch(MyLatch);
@@ -2222,8 +2201,8 @@ WalSndLoop(WalSndSendDataCallback send_data)
long sleeptime;
int wakeEvents;
- wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_TIMEOUT |
- WL_SOCKET_READABLE;
+ wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH | WL_TIMEOUT |
+ WL_SOCKET_READABLE;
/*
* Use fresh timestamp, not last_processed, to reduce the chance
@@ -2235,9 +2214,9 @@ WalSndLoop(WalSndSendDataCallback send_data)
wakeEvents |= WL_SOCKET_WRITEABLE;
/* Sleep until something happens or we time out */
- WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime,
- WAIT_EVENT_WAL_SENDER_MAIN);
+ (void) WaitLatchOrSocket(MyLatch, wakeEvents,
+ MyProcPort->sock, sleeptime,
+ WAIT_EVENT_WAL_SENDER_MAIN);
}
}
return;
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index c129446f9c9..ed23be28f3f 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -48,6 +48,7 @@
#include "port/atomics.h"
#include "portability/instr_time.h"
#include "postmaster/postmaster.h"
+#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/shmem.h"
@@ -92,6 +93,13 @@ struct WaitEventSet
Latch *latch;
int latch_pos;
+ /*
+ * WL_EXIT_ON_PM_DEATH is converted to WL_POSTMASTER_DEATH, but this flag
+ * is set so that we'll exit immediately if postmaster death is detected,
+ * instead of returning.
+ */
+ bool exit_on_postmaster_death;
+
#if defined(WAIT_USE_EPOLL)
int epoll_fd;
/* epoll_wait returns events in a user provided arrays, allocate once */
@@ -348,6 +356,11 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
* to be reported as readable/writable/connected, so that the caller can deal
* with the condition.
*
+ * wakeEvents must include either WL_EXIT_ON_PM_DEATH for automatic exit
+ * if the postmaster dies or WL_POSTMASTER_DEATH for a flag set in the
+ * return value if the postmaster dies. The latter is useful for rare cases
+ * where some behavior other than immediate exit is needed.
+ *
* NB: These days this is just a wrapper around the WaitEventSet API. When
* using a latch very frequently, consider creating a longer living
* WaitEventSet instead; that's more efficient.
@@ -370,10 +383,19 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, WL_LATCH_SET, PGINVALID_SOCKET,
(Latch *) latch, NULL);
- if (wakeEvents & WL_POSTMASTER_DEATH && IsUnderPostmaster)
+ /* Postmaster-managed callers must handle postmaster death somehow. */
+ Assert(!IsUnderPostmaster ||
+ (wakeEvents & WL_EXIT_ON_PM_DEATH) ||
+ (wakeEvents & WL_POSTMASTER_DEATH));
+
+ if ((wakeEvents & WL_POSTMASTER_DEATH) && IsUnderPostmaster)
AddWaitEventToSet(set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
NULL, NULL);
+ if ((wakeEvents & WL_EXIT_ON_PM_DEATH) && IsUnderPostmaster)
+ AddWaitEventToSet(set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
+ NULL, NULL);
+
if (wakeEvents & WL_SOCKET_MASK)
{
int ev;
@@ -562,6 +584,7 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->latch = NULL;
set->nevents_space = nevents;
+ set->exit_on_postmaster_death = false;
#if defined(WAIT_USE_EPOLL)
#ifdef EPOLL_CLOEXEC
@@ -646,6 +669,7 @@ FreeWaitEventSet(WaitEventSet *set)
* - WL_SOCKET_CONNECTED: Wait for socket connection to be established,
* can be combined with other WL_SOCKET_* events (on non-Windows
* platforms, this is the same as WL_SOCKET_WRITEABLE)
+ * - WL_EXIT_ON_PM_DEATH: Exit immediately if the postmaster dies
*
* Returns the offset in WaitEventSet->events (starting from 0), which can be
* used to modify previously added wait events using ModifyWaitEvent().
@@ -671,6 +695,12 @@ AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd, Latch *latch,
/* not enough space */
Assert(set->nevents < set->nevents_space);
+ if (events == WL_EXIT_ON_PM_DEATH)
+ {
+ events = WL_POSTMASTER_DEATH;
+ set->exit_on_postmaster_death = true;
+ }
+
if (latch)
{
if (latch->owner_pid != MyProcPid)
@@ -986,7 +1016,6 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
occurred_events->user_data =
set->events[set->latch_pos].user_data;
occurred_events->events = WL_LATCH_SET;
- occurred_events++;
returned_events++;
break;
@@ -1114,6 +1143,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
*/
if (!PostmasterIsAliveInternal())
{
+ if (set->exit_on_postmaster_death)
+ proc_exit(1);
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
occurred_events++;
@@ -1232,6 +1263,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
*/
if (!PostmasterIsAliveInternal())
{
+ if (set->exit_on_postmaster_death)
+ proc_exit(1);
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
occurred_events++;
@@ -1392,6 +1425,8 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
*/
if (!PostmasterIsAliveInternal())
{
+ if (set->exit_on_postmaster_death)
+ proc_exit(1);
occurred_events->fd = PGINVALID_SOCKET;
occurred_events->events = WL_POSTMASTER_DEATH;
occurred_events++;
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index fde71afd479..ec0ddd537ba 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -949,7 +949,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_SEND);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_SEND);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1093,7 +1094,8 @@ shm_mq_receive_bytes(shm_mq_handle *mqh, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_RECEIVE);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_RECEIVE);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1181,7 +1183,8 @@ shm_mq_wait_internal(shm_mq *mq, PGPROC **ptr, BackgroundWorkerHandle *handle)
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, WAIT_EVENT_MQ_INTERNAL);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ WAIT_EVENT_MQ_INTERNAL);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/condition_variable.c b/src/backend/storage/lmgr/condition_variable.c
index ef1d5baf016..7f75ee61cd6 100644
--- a/src/backend/storage/lmgr/condition_variable.c
+++ b/src/backend/storage/lmgr/condition_variable.c
@@ -72,7 +72,7 @@ ConditionVariablePrepareToSleep(ConditionVariable *cv)
new_event_set = CreateWaitEventSet(TopMemoryContext, 2);
AddWaitEventToSet(new_event_set, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
- AddWaitEventToSet(new_event_set, WL_POSTMASTER_DEATH, PGINVALID_SOCKET,
+ AddWaitEventToSet(new_event_set, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
/* Don't set cv_wait_event_set until we have a correct WES. */
cv_wait_event_set = new_event_set;
@@ -154,16 +154,8 @@ ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
* Wait for latch to be set. (If we're awakened for some other
* reason, the code below will cope anyway.)
*/
- WaitEventSetWait(cv_wait_event_set, -1, &event, 1, wait_event_info);
-
- if (event.events & WL_POSTMASTER_DEATH)
- {
- /*
- * Emergency bailout if postmaster has died. This is to avoid the
- * necessity for manual cleanup of all postmaster children.
- */
- exit(1);
- }
+ (void) WaitEventSetWait(cv_wait_event_set, -1, &event, 1,
+ wait_event_info);
/* Reset latch before examining the state of the wait list. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 6ad504453b1..33387fb71bc 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1270,8 +1270,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0,
- PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_LOCK | locallock->tag.lock.locktag_type);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
if (got_deadlock_timeout)
@@ -1783,7 +1783,8 @@ CheckDeadLockAlert(void)
void
ProcWaitForSignal(uint32 wait_event_info)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event_info);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ wait_event_info);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 309eb2935c7..746fb29c59d 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -379,7 +379,7 @@ pg_sleep(PG_FUNCTION_ARGS)
break;
(void) WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
delay_ms,
WAIT_EVENT_PG_SLEEP);
ResetLatch(MyLatch);
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index fd8735b7f5f..039a82e1a3a 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -126,8 +126,9 @@ typedef struct Latch
#define WL_SOCKET_WRITEABLE (1 << 2)
#define WL_TIMEOUT (1 << 3) /* not for WaitEventSetWait() */
#define WL_POSTMASTER_DEATH (1 << 4)
+#define WL_EXIT_ON_PM_DEATH (1 << 5)
#ifdef WIN32
-#define WL_SOCKET_CONNECTED (1 << 5)
+#define WL_SOCKET_CONNECTED (1 << 6)
#else
/* avoid having to deal with case on platforms not requiring it */
#define WL_SOCKET_CONNECTED WL_SOCKET_WRITEABLE
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 97e8617b3e9..75f76b2c363 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -280,7 +280,8 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index ebab9866017..d03be06ff65 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -231,7 +231,8 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0, PG_WAIT_EXTENSION);
+ (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+ PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 0d705a3f2ed..52a3208527e 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -226,15 +226,11 @@ worker_spi_main(Datum main_arg)
* background process goes away immediately in an emergency.
*/
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
worker_spi_naptime * 1000L,
PG_WAIT_EXTENSION);
ResetLatch(MyLatch);
- /* emergency bailout if postmaster has died */
- if (rc & WL_POSTMASTER_DEATH)
- proc_exit(1);
-
CHECK_FOR_INTERRUPTS();
/*
--
2.19.1
On Sat, Nov 17, 2018 at 2:27 PM Thomas Munro
<thomas.munro@enterprisedb.com> wrote:
Thanks for the review.
Pushed.
--
Thomas Munro
http://www.enterprisedb.com