@@ -78,6 +78,8 @@ typedef struct BackgroundWorkerSlot
7878 pid_t pid ; /* InvalidPid = not started yet; 0 = dead */
7979 uint64 generation ; /* incremented when slot is recycled */
8080 BackgroundWorker worker ;
81+ int notify_pmchild ;
82+ ProcNumber notify_proc_number ;
8183} BackgroundWorkerSlot ;
8284
8385/*
@@ -192,8 +194,9 @@ BackgroundWorkerShmemInit(void)
192194 slot -> terminate = false;
193195 slot -> pid = InvalidPid ;
194196 slot -> generation = 0 ;
197+ slot -> notify_pmchild = 0 ;
198+ slot -> notify_proc_number = INVALID_PROC_NUMBER ;
195199 rw -> rw_shmem_slot = slotno ;
196- rw -> rw_worker .bgw_notify_pid = 0 ; /* might be reinit after crash */
197200 memcpy (& slot -> worker , & rw -> rw_worker , sizeof (BackgroundWorker ));
198201 ++ slotno ;
199202 }
@@ -234,6 +237,14 @@ FindRegisteredWorkerBySlotNumber(int slotno)
234237 return NULL ;
235238}
236239
240+ ProcNumber
241+ GetNotifyProcNumberForRegisteredWorker (RegisteredBgWorker * rw )
242+ {
243+ BackgroundWorkerSlot * slot = & BackgroundWorkerData -> slot [rw -> rw_shmem_slot ];
244+
245+ return slot -> notify_proc_number ;
246+ }
247+
237248/*
238249 * Notice changes to shared memory made by other backends.
239250 * Accept new worker requests only if allow_new_workers is true.
@@ -315,29 +326,29 @@ BackgroundWorkerStateChange(bool allow_new_workers)
315326 /*
316327 * If the worker is marked for termination, we don't need to add it to
317328 * the registered workers list; we can just free the slot. However, if
318- * bgw_notify_pid is set, the process that registered the worker may
319- * need to know that we've processed the terminate request, so be sure
320- * to signal it.
329+ * bgw_notify_proc_number is set, the process that registered the
330+ * worker may need to know that we've processed the terminate request,
331+ * so be sure to signal it.
321332 */
322333 if (slot -> terminate )
323334 {
324- int notify_pid ;
335+ int notify_proc_number ;
325336
326337 /*
327338 * We need a memory barrier here to make sure that the load of
328- * bgw_notify_pid and the update of parallel_terminate_count
329- * complete before the store to in_use.
339+ * bgw_notify_proc_number and the update of
340+ * parallel_terminate_count complete before the store to in_use.
330341 */
331- notify_pid = slot -> worker . bgw_notify_pid ;
342+ notify_proc_number = slot -> notify_proc_number ;
332343 if ((slot -> worker .bgw_flags & BGWORKER_CLASS_PARALLEL ) != 0 )
333344 BackgroundWorkerData -> parallel_terminate_count ++ ;
334345 slot -> pid = 0 ;
335346
336347 pg_memory_barrier ();
337348 slot -> in_use = false;
338349
339- if (notify_pid != 0 )
340- kill ( notify_pid , SIGUSR1 );
350+ if (notify_proc_number != INVALID_PROC_NUMBER )
351+ SendInterrupt ( INTERRUPT_GENERAL , notify_proc_number );
341352
342353 continue ;
343354 }
@@ -383,23 +394,6 @@ BackgroundWorkerStateChange(bool allow_new_workers)
383394 rw -> rw_worker .bgw_main_arg = slot -> worker .bgw_main_arg ;
384395 memcpy (rw -> rw_worker .bgw_extra , slot -> worker .bgw_extra , BGW_EXTRALEN );
385396
386- /*
387- * Copy the PID to be notified about state changes, but only if the
388- * postmaster knows about a backend with that PID. It isn't an error
389- * if the postmaster doesn't know about the PID, because the backend
390- * that requested the worker could have died (or been killed) just
391- * after doing so. Nonetheless, at least until we get some experience
392- * with how this plays out in the wild, log a message at a relative
393- * high debug level.
394- */
395- rw -> rw_worker .bgw_notify_pid = slot -> worker .bgw_notify_pid ;
396- if (!PostmasterMarkPIDForWorkerNotify (rw -> rw_worker .bgw_notify_pid ))
397- {
398- elog (DEBUG1 , "worker notification PID %d is not valid" ,
399- (int ) rw -> rw_worker .bgw_notify_pid );
400- rw -> rw_worker .bgw_notify_pid = 0 ;
401- }
402-
403397 /* Initialize postmaster bookkeeping. */
404398 rw -> rw_pid = 0 ;
405399 rw -> rw_crashed_at = 0 ;
@@ -421,7 +415,7 @@ BackgroundWorkerStateChange(bool allow_new_workers)
421415 * NOTE: The entry is unlinked from BackgroundWorkerList. If the caller is
422416 * iterating through it, better use a mutable iterator!
423417 *
424- * Caller is responsible for notifying bgw_notify_pid , if appropriate.
418+ * Caller is responsible for notifying bgw_notify_proc_number , if appropriate.
425419 *
426420 * This function must be invoked only in the postmaster.
427421 */
@@ -466,8 +460,8 @@ ReportBackgroundWorkerPID(RegisteredBgWorker *rw)
466460 slot = & BackgroundWorkerData -> slot [rw -> rw_shmem_slot ];
467461 slot -> pid = rw -> rw_pid ;
468462
469- if (rw -> rw_worker . bgw_notify_pid != 0 )
470- kill ( rw -> rw_worker . bgw_notify_pid , SIGUSR1 );
463+ if (slot -> notify_proc_number != INVALID_PROC_NUMBER )
464+ SendInterrupt ( INTERRUPT_GENERAL , slot -> notify_proc_number );
471465}
472466
473467/*
@@ -483,12 +477,12 @@ void
483477ReportBackgroundWorkerExit (RegisteredBgWorker * rw )
484478{
485479 BackgroundWorkerSlot * slot ;
486- int notify_pid ;
480+ ProcNumber notify_proc_number ;
487481
488482 Assert (rw -> rw_shmem_slot < max_worker_processes );
489483 slot = & BackgroundWorkerData -> slot [rw -> rw_shmem_slot ];
490484 slot -> pid = rw -> rw_pid ;
491- notify_pid = rw -> rw_worker . bgw_notify_pid ;
485+ notify_proc_number = slot -> notify_proc_number ;
492486
493487 /*
494488 * If this worker is slated for deregistration, do that before notifying
@@ -501,27 +495,34 @@ ReportBackgroundWorkerExit(RegisteredBgWorker *rw)
501495 rw -> rw_worker .bgw_restart_time == BGW_NEVER_RESTART )
502496 ForgetBackgroundWorker (rw );
503497
504- if (notify_pid != 0 )
505- kill ( notify_pid , SIGUSR1 );
498+ if (notify_proc_number != INVALID_PROC_NUMBER )
499+ SendInterrupt ( INTERRUPT_GENERAL , notify_proc_number );
506500}
507501
508502/*
509- * Cancel SIGUSR1 notifications for a PID belonging to an exiting backend.
503+ * Cancel notifications for a PID belonging to an exiting backend.
510504 *
511505 * This function should only be called from the postmaster.
512506 */
513507void
514- BackgroundWorkerStopNotifications (pid_t pid )
508+ BackgroundWorkerStopNotifications (int pmchild )
515509{
516510 dlist_iter iter ;
517511
518512 dlist_foreach (iter , & BackgroundWorkerList )
519513 {
520514 RegisteredBgWorker * rw ;
515+ BackgroundWorkerSlot * slot ;
521516
522517 rw = dlist_container (RegisteredBgWorker , rw_lnode , iter .cur );
523- if (rw -> rw_worker .bgw_notify_pid == pid )
524- rw -> rw_worker .bgw_notify_pid = 0 ;
518+ Assert (rw -> rw_shmem_slot < max_worker_processes );
519+ slot = & BackgroundWorkerData -> slot [rw -> rw_shmem_slot ];
520+
521+ if (slot -> notify_pmchild == pmchild )
522+ {
523+ slot -> notify_pmchild = 0 ;
524+ slot -> notify_proc_number = INVALID_PROC_NUMBER ;
525+ }
525526 }
526527}
527528
@@ -553,14 +554,14 @@ ForgetUnstartedBackgroundWorkers(void)
553554
554555 /* If it's not yet started, and there's someone waiting ... */
555556 if (slot -> pid == InvalidPid &&
556- rw -> rw_worker . bgw_notify_pid != 0 )
557+ slot -> notify_proc_number != INVALID_PROC_NUMBER )
557558 {
558559 /* ... then zap it, and notify the waiter */
559- int notify_pid = rw -> rw_worker . bgw_notify_pid ;
560+ int notify_proc_number = slot -> notify_proc_number ;
560561
561562 ForgetBackgroundWorker (rw );
562- if (notify_pid != 0 )
563- kill ( notify_pid , SIGUSR1 );
563+ if (notify_proc_number != INVALID_PROC_NUMBER )
564+ SendInterrupt ( INTERRUPT_GENERAL , notify_proc_number );
564565 }
565566 }
566567}
@@ -613,11 +614,6 @@ ResetBackgroundWorkerCrashTimes(void)
613614 * resetting.
614615 */
615616 rw -> rw_crashed_at = 0 ;
616-
617- /*
618- * If there was anyone waiting for it, they're history.
619- */
620- rw -> rw_worker .bgw_notify_pid = 0 ;
621617 }
622618 }
623619}
@@ -981,15 +977,6 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
981977 if (!SanityCheckBackgroundWorker (worker , LOG ))
982978 return ;
983979
984- if (worker -> bgw_notify_pid != 0 )
985- {
986- ereport (LOG ,
987- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
988- errmsg ("background worker \"%s\": only dynamic background workers can request notification" ,
989- worker -> bgw_name )));
990- return ;
991- }
992-
993980 /*
994981 * Enforce maximum number of workers. Note this is overly restrictive: we
995982 * could allow more non-shmem-connected workers, because these don't count
@@ -1105,6 +1092,25 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
11051092 if (parallel )
11061093 BackgroundWorkerData -> parallel_register_count ++ ;
11071094
1095+ if ((slot -> worker .bgw_flags & BGWORKER_SHMEM_ACCESS ) != 0 &&
1096+ (slot -> worker .bgw_flags & BGWORKER_NO_NOTIFY ) == 0 )
1097+ {
1098+ /*
1099+ * Set notify_proc_number so that postmaster will send us an
1100+ * interrupt. Also remember the pmchild slot number;
1101+ * postmaster needs it to detect when we exit, to disarm the
1102+ * notification.
1103+ */
1104+ slot -> notify_pmchild = MyPMChildSlot ;
1105+ slot -> notify_proc_number = MyProcNumber ;
1106+ }
1107+ else
1108+ {
1109+ /* No notifications. */
1110+ slot -> notify_pmchild = 0 ;
1111+ slot -> notify_proc_number = INVALID_PROC_NUMBER ;
1112+ }
1113+
11081114 /*
11091115 * Make sure postmaster doesn't see the slot as in use before it
11101116 * sees the new contents.
@@ -1205,8 +1211,9 @@ GetBackgroundWorkerPid(BackgroundWorkerHandle *handle, pid_t *pidp)
12051211 * BGWH_POSTMASTER_DIED, since it that case we know that startup will not
12061212 * take place.
12071213 *
1208- * The caller *must* have set our PID as the worker's bgw_notify_pid,
1209- * else we will not be awoken promptly when the worker's state changes.
1214+ * This works only if the worker was registered with BGWORKER_SHMEM_ACCESS and
1215+ * without BGWORKER_NO_NOTIFY, else we will not be awoken promptly when the
1216+ * worker's state changes.
12101217 */
12111218BgwHandleStatus
12121219WaitForBackgroundWorkerStartup (BackgroundWorkerHandle * handle , pid_t * pidp )
@@ -1250,8 +1257,9 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
12501257 * up and return BGWH_POSTMASTER_DIED, because it's the postmaster that
12511258 * notifies us when a worker's state changes.
12521259 *
1253- * The caller *must* have set our PID as the worker's bgw_notify_pid,
1254- * else we will not be awoken promptly when the worker's state changes.
1260+ * This works only if the worker was registered with BGWORKER_SHMEM_ACCESS and
1261+ * without BGWORKER_NO_NOTIFY, else we will not be awoken promptly when the
1262+ * worker's state changes.
12551263 */
12561264BgwHandleStatus
12571265WaitForBackgroundWorkerShutdown (BackgroundWorkerHandle * handle )
0 commit comments