@@ -55,6 +55,11 @@ slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
55
55
* must fully initialize the slot - and insert a write memory barrier - before
56
56
* marking it as in use.
57
57
*
58
+ * As an exception, however, even when the slot is in use, regular backends
59
+ * may set the 'terminate' flag for a slot, telling the postmaster not
60
+ * to restart it. Once the background worker is no longer running, the slot
61
+ * will be released for reuse.
62
+ *
58
63
* In addition to coordinating with the postmaster, backends modifying this
59
64
* data structure must coordinate with each other. Since they can take locks,
60
65
* this is straightforward: any backend wishing to manipulate a slot must
@@ -67,6 +72,7 @@ slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
67
72
typedef struct BackgroundWorkerSlot
68
73
{
69
74
bool in_use ;
75
+ bool terminate ;
70
76
pid_t pid ; /* InvalidPid = not started yet; 0 = dead */
71
77
uint64 generation ; /* incremented when slot is recycled */
72
78
BackgroundWorker worker ;
@@ -134,6 +140,7 @@ BackgroundWorkerShmemInit(void)
134
140
rw = slist_container (RegisteredBgWorker , rw_lnode , siter .cur );
135
141
Assert (slotno < max_worker_processes );
136
142
slot -> in_use = true;
143
+ slot -> terminate = false;
137
144
slot -> pid = InvalidPid ;
138
145
slot -> generation = 0 ;
139
146
rw -> rw_shmem_slot = slotno ;
@@ -223,14 +230,29 @@ BackgroundWorkerStateChange(void)
223
230
*/
224
231
pg_read_barrier ();
225
232
226
- /*
227
- * See whether we already know about this worker. If not, we need
228
- * to update our backend-private BackgroundWorkerList to match shared
229
- * memory.
230
- */
233
+ /* See whether we already know about this worker. */
231
234
rw = FindRegisteredWorkerBySlotNumber (slotno );
232
235
if (rw != NULL )
236
+ {
237
+ /*
238
+ * In general, the worker data can't change after it's initially
239
+ * registered. However, someone can set the terminate flag.
240
+ */
241
+ if (slot -> terminate && !rw -> rw_terminate )
242
+ {
243
+ rw -> rw_terminate = true;
244
+ if (rw -> rw_pid != 0 )
245
+ kill (rw -> rw_pid , SIGTERM );
246
+ }
233
247
continue ;
248
+ }
249
+
250
+ /* If it's already flagged as do not restart, just release the slot. */
251
+ if (slot -> terminate )
252
+ {
253
+ slot -> in_use = false;
254
+ continue ;
255
+ }
234
256
235
257
/*
236
258
* Copy the registration data into the registered workers list.
@@ -292,6 +314,7 @@ BackgroundWorkerStateChange(void)
292
314
rw -> rw_child_slot = 0 ;
293
315
rw -> rw_crashed_at = 0 ;
294
316
rw -> rw_shmem_slot = slotno ;
317
+ rw -> rw_terminate = false;
295
318
296
319
/* Log it! */
297
320
ereport (LOG ,
@@ -714,6 +737,7 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
714
737
rw -> rw_pid = 0 ;
715
738
rw -> rw_child_slot = 0 ;
716
739
rw -> rw_crashed_at = 0 ;
740
+ rw -> rw_terminate = false;
717
741
718
742
slist_push_head (& BackgroundWorkerList , & rw -> rw_lnode );
719
743
}
@@ -764,6 +788,7 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
764
788
memcpy (& slot -> worker , worker , sizeof (BackgroundWorker ));
765
789
slot -> pid = InvalidPid ; /* indicates not started yet */
766
790
slot -> generation ++ ;
791
+ slot -> terminate = false;
767
792
generation = slot -> generation ;
768
793
769
794
/*
@@ -905,3 +930,33 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
905
930
set_latch_on_sigusr1 = save_set_latch_on_sigusr1 ;
906
931
return status ;
907
932
}
933
+
934
+ /*
935
+ * Instruct the postmaster to terminate a background worker.
936
+ *
937
+ * Note that it's safe to do this without regard to whether the worker is
938
+ * still running, or even if the worker may already have existed and been
939
+ * unregistered.
940
+ */
941
+ void
942
+ TerminateBackgroundWorker (BackgroundWorkerHandle * handle )
943
+ {
944
+ BackgroundWorkerSlot * slot ;
945
+ bool signal_postmaster = false;
946
+
947
+ Assert (handle -> slot < max_worker_processes );
948
+ slot = & BackgroundWorkerData -> slot [handle -> slot ];
949
+
950
+ /* Set terminate flag in shared memory, unless slot has been reused. */
951
+ LWLockAcquire (BackgroundWorkerLock , LW_EXCLUSIVE );
952
+ if (handle -> generation == slot -> generation )
953
+ {
954
+ slot -> terminate = true;
955
+ signal_postmaster = true;
956
+ }
957
+ LWLockRelease (BackgroundWorkerLock );
958
+
959
+ /* Make sure the postmaster notices the change to shared memory. */
960
+ if (signal_postmaster )
961
+ SendPostmasterSignal (PMSIGNAL_BACKGROUND_WORKER_CHANGE );
962
+ }
0 commit comments