diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index f57224c..c49b97b 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -332,20 +332,21 @@ BackgroundWorkerStateChange(void) rw->rw_worker.bgw_notify_pid = 0; } /* Initialize postmaster bookkeeping. */ rw->rw_backend = NULL; rw->rw_pid = 0; rw->rw_child_slot = 0; rw->rw_crashed_at = 0; rw->rw_shmem_slot = slotno; rw->rw_terminate = false; + rw->rw_notify = false; /* Log it! */ ereport(LOG, (errmsg("registering background worker \"%s\"", rw->rw_worker.bgw_name))); slist_push_head(&BackgroundWorkerList, &rw->rw_lnode); } } @@ -796,20 +797,21 @@ RegisterBackgroundWorker(BackgroundWorker *worker) errmsg("out of memory"))); return; } rw->rw_worker = *worker; rw->rw_backend = NULL; rw->rw_pid = 0; rw->rw_child_slot = 0; rw->rw_crashed_at = 0; rw->rw_terminate = false; + rw->rw_notify = false; slist_push_head(&BackgroundWorkerList, &rw->rw_lnode); } /* * Register a new background worker from a regular backend. * * Returns true on success and false on failure. Failure typically indicates * that no background worker slots are currently available. * diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 1757b4d..77cd3e0 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -2919,20 +2919,30 @@ CleanupBackgroundWorker(int pid, if ((rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS) != 0) { if (!EXIT_STATUS_0(exitstatus) && !EXIT_STATUS_1(exitstatus)) { HandleChildCrash(pid, exitstatus, namebuf); return true; } } /* + * It's possible that this background worker started some OTHER + * background worker and asked to be notified when that worker + * started or stopped. If so, cancel any notifications destined + * for the now-dead background worker. Backends are dealt with + * separately below. + */ + if (!rw->rw_backend && rw->rw_notify) + BackgroundWorkerStopNotifications(rw->rw_pid); + + /* * We must release the postmaster child slot whether this worker is * connected to shared memory or not, but we only treat it as a crash * if it is in fact connected. */ if (!ReleasePostmasterChildSlot(rw->rw_child_slot) && (rw->rw_worker.bgw_flags & BGWORKER_SHMEM_ACCESS) != 0) { HandleChildCrash(pid, exitstatus, namebuf); return true; } @@ -2952,20 +2962,21 @@ CleanupBackgroundWorker(int pid, * started or stopped. If so, cancel any notifications destined * for the now-dead backend. */ if (rw->rw_backend->bgworker_notify) BackgroundWorkerStopNotifications(rw->rw_pid); free(rw->rw_backend); rw->rw_backend = NULL; } rw->rw_pid = 0; rw->rw_child_slot = 0; + rw->rw_notify = false; ReportBackgroundWorkerPID(rw); /* report child death */ LogChildExit(LOG, namebuf, pid, exitstatus); return true; } return false; } @@ -3102,20 +3113,21 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) { dlist_delete(&rw->rw_backend->elem); #ifdef EXEC_BACKEND ShmemBackendArrayRemove(rw->rw_backend); #endif free(rw->rw_backend); rw->rw_backend = NULL; } rw->rw_pid = 0; rw->rw_child_slot = 0; + rw->rw_notify = false; /* don't reset crashed_at */ /* don't report child stop, either */ /* Keep looping so we can signal remaining workers */ } else { /* * This worker is still alive. Unless we did so already, tell it * to commit hara-kiri. * @@ -5653,31 +5665,43 @@ maybe_start_bgworker(void) /* * When a backend asks to be notified about worker state changes, we * set a flag in its backend entry. The background worker machinery needs * to know when such backends exit. */ bool PostmasterMarkPIDForWorkerNotify(int pid) { dlist_iter iter; + slist_iter siter; Backend *bp; dlist_foreach(iter, &BackendList) { bp = dlist_container(Backend, elem, iter.cur); if (bp->pid == pid) { bp->bgworker_notify = true; return true; } } + + slist_foreach(siter, &BackgroundWorkerList) + { + RegisteredBgWorker *rbgw; + rbgw = slist_container(RegisteredBgWorker, rw_lnode, siter.cur); + if (rbgw->rw_pid == pid) + { + rbgw->rw_notify = true; + return true; + } + } return false; } #ifdef EXEC_BACKEND /* * The following need to be available to the save/restore_backend_variables * functions. They are marked NON_EXEC_STATIC in their home modules. */ extern slock_t *ShmemLock; diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h index b0ab4c2..5ecaeca 100644 --- a/src/include/postmaster/bgworker_internals.h +++ b/src/include/postmaster/bgworker_internals.h @@ -25,20 +25,21 @@ */ typedef struct RegisteredBgWorker { BackgroundWorker rw_worker; /* its registry entry */ struct bkend *rw_backend; /* its BackendList entry, or NULL */ pid_t rw_pid; /* 0 if not running */ int rw_child_slot; TimestampTz rw_crashed_at; /* if not 0, time it last crashed */ int rw_shmem_slot; bool rw_terminate; + bool rw_notify; /* gets background worker start/stop notifications */ slist_node rw_lnode; /* list link */ } RegisteredBgWorker; extern slist_head BackgroundWorkerList; extern Size BackgroundWorkerShmemSize(void); extern void BackgroundWorkerShmemInit(void); extern void BackgroundWorkerStateChange(void); extern void ForgetBackgroundWorker(slist_mutable_iter *cur); extern void ReportBackgroundWorkerPID(RegisteredBgWorker *);