aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2021-05-15 12:21:06 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2021-05-15 12:21:06 -0400
commitc3cc73e144246c253442aa2aa031749d57eb710b (patch)
tree780b928b8af098aae12e39894de061c9cb373bc5
parentfa675af59fc828d0b71bd9139042d71456640a28 (diff)
downloadpostgresql-c3cc73e144246c253442aa2aa031749d57eb710b.tar.gz
postgresql-c3cc73e144246c253442aa2aa031749d57eb710b.zip
Be more careful about barriers when releasing BackgroundWorkerSlots.
ForgetBackgroundWorker lacked any memory barrier at all, while BackgroundWorkerStateChange had one but unaccountably did additional manipulation of the slot after the barrier. AFAICS, the rule must be that the barrier is immediately before setting or clearing slot->in_use. It looks like back in 9.6 when ForgetBackgroundWorker was first written, there might have been some case for not needing a barrier there, but I'm not very convinced of that --- the fact that the load of bgw_notify_pid is in the caller doesn't seem to guarantee no memory ordering problem. So patch 9.6 too. It's likely that this doesn't fix any observable bug on Intel hardware, but machines with weaker memory ordering rules could have problems here. Discussion: https://postgr.es/m/4046084.1620244003@sss.pgh.pa.us
-rw-r--r--src/backend/postmaster/bgworker.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 4a5c0e5509b..9bf3ead8d2e 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -327,9 +327,11 @@ BackgroundWorkerStateChange(bool allow_new_workers)
notify_pid = slot->worker.bgw_notify_pid;
if ((slot->worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
BackgroundWorkerData->parallel_terminate_count++;
- pg_memory_barrier();
slot->pid = 0;
+
+ pg_memory_barrier();
slot->in_use = false;
+
if (notify_pid != 0)
kill(notify_pid, SIGUSR1);
@@ -416,6 +418,8 @@ BackgroundWorkerStateChange(bool allow_new_workers)
* points to it. This convention allows deletion of workers during
* searches of the worker list, and saves having to search the list again.
*
+ * Caller is responsible for notifying bgw_notify_pid, if appropriate.
+ *
* This function must be invoked only in the postmaster.
*/
void
@@ -428,9 +432,16 @@ ForgetBackgroundWorker(slist_mutable_iter *cur)
Assert(rw->rw_shmem_slot < max_worker_processes);
slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
+ Assert(slot->in_use);
+
+ /*
+ * We need a memory barrier here to make sure that the update of
+ * parallel_terminate_count completes before the store to in_use.
+ */
if ((rw->rw_worker.bgw_flags & BGWORKER_CLASS_PARALLEL) != 0)
BackgroundWorkerData->parallel_terminate_count++;
+ pg_memory_barrier();
slot->in_use = false;
ereport(DEBUG1,