aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage')
-rw-r--r--src/backend/storage/ipc/latch.c38
-rw-r--r--src/backend/storage/ipc/shm_mq.c9
-rw-r--r--src/backend/storage/lmgr/condition_variable.c14
-rw-r--r--src/backend/storage/lmgr/proc.c7
4 files changed, 50 insertions, 18 deletions
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index c129446f9c9..b0804537cf3 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 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();
}