diff --git a/- b/- new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c index 03bf90ce2d..c2a6e5a53f 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 fe4893a8e0..a6509932dc 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 84197192ec..b9a9ae5c73 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 80616c5f1e..7397b6ee06 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -6189,10 +6189,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; } @@ -12093,9 +12093,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(); } @@ -12269,9 +12271,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 bd18f496af..f139eeff9f 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 c979a55774..e6367ade76 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 a910ea2cb4..2ca11c2409 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -410,8 +410,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 6eaed5bf0c..603d9016fd 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 31e98db9d6..2d5086d406 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 54a042843d..bd8dc61182 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -335,7 +335,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); /* @@ -362,20 +362,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 9eac86b554..b9c118e156 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -340,7 +340,6 @@ CheckpointerMain(void) pg_time_t now; int elapsed_secs; int cur_timeout; - int rc; /* Clear any already-pending wakeups */ ResetLatch(MyLatch); @@ -541,17 +540,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 0ebd63650c..844b9d1b0e 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -390,6 +390,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; @@ -400,7 +402,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 3575513889..fbeee31109 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; @@ -294,13 +295,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; @@ -436,25 +453,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; @@ -501,10 +511,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 3e09827854..0ae733e886 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -223,7 +223,6 @@ WalWriterMain(void) for (;;) { long cur_timeout; - int rc; /* * Advertise whether we might hibernate in this cycle. We do this @@ -276,17 +275,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 b20f6c379c..a7e3db2783 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 e2b54265d7..9b75711ebd 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 ce089ac07c..3a84d8ca86 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 9e682331d2..38ae1b9ab8 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 3cd1e0d728..8d5e0946c4 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 af5ad5fe66..9a13c50ce8 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 cb7bb47c9b..9643c2ed7b 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -503,7 +503,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, @@ -524,15 +524,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) { /* @@ -673,13 +664,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); @@ -706,8 +690,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 50191ba881..46edb525e8 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 c129446f9c..b0804537cf 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) @@ -1114,6 +1144,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 +1264,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 +1426,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 fde71afd47..ec0ddd537b 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 ef1d5baf01..7f75ee61cd 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 6ad504453b..33387fb71b 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 d05849f1d4..b8f86973dc 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 fd8735b7f5..039a82e1a3 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 97e8617b3e..75f76b2c36 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 ebab986601..d03be06ff6 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 0d705a3f2e..52a3208527 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(); /*