@@ -320,7 +320,7 @@ SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
320
320
uint64
321
321
EmitProcSignalBarrier (ProcSignalBarrierType type )
322
322
{
323
- uint64 flagbit = UINT64CONST ( 1 ) << (uint64 ) type ;
323
+ uint32 flagbit = 1 << (uint32 ) type ;
324
324
uint64 generation ;
325
325
326
326
/*
@@ -363,7 +363,11 @@ EmitProcSignalBarrier(ProcSignalBarrierType type)
363
363
pid_t pid = slot -> pss_pid ;
364
364
365
365
if (pid != 0 )
366
+ {
367
+ /* see SendProcSignal for details */
368
+ slot -> pss_signalFlags [PROCSIG_BARRIER ] = true;
366
369
kill (pid , SIGUSR1 );
370
+ }
367
371
}
368
372
369
373
return generation ;
@@ -383,6 +387,8 @@ WaitForProcSignalBarrier(uint64 generation)
383
387
{
384
388
long timeout = 125L ;
385
389
390
+ Assert (generation <= pg_atomic_read_u64 (& ProcSignal -> psh_barrierGeneration ));
391
+
386
392
for (int i = NumProcSignalSlots - 1 ; i >= 0 ; i -- )
387
393
{
388
394
volatile ProcSignalSlot * slot = & ProcSignal -> psh_slot [i ];
@@ -417,6 +423,23 @@ WaitForProcSignalBarrier(uint64 generation)
417
423
pg_memory_barrier ();
418
424
}
419
425
426
+ /*
427
+ * Handle receipt of an interrupt indicating a global barrier event.
428
+ *
429
+ * All the actual work is deferred to ProcessProcSignalBarrier(), because we
430
+ * cannot safely access the barrier generation inside the signal handler as
431
+ * 64bit atomics might use spinlock based emulation, even for reads. As this
432
+ * routine only gets called when PROCSIG_BARRIER is sent that won't cause a
433
+ * lot fo unnecessary work.
434
+ */
435
+ static void
436
+ HandleProcSignalBarrierInterrupt (void )
437
+ {
438
+ InterruptPending = true;
439
+ ProcSignalBarrierPending = true;
440
+ /* latch will be set by procsignal_sigusr1_handler */
441
+ }
442
+
420
443
/*
421
444
* Perform global barrier related interrupt checking.
422
445
*
@@ -428,22 +451,38 @@ WaitForProcSignalBarrier(uint64 generation)
428
451
void
429
452
ProcessProcSignalBarrier (void )
430
453
{
431
- uint64 generation ;
454
+ uint64 local_gen ;
455
+ uint64 shared_gen ;
432
456
uint32 flags ;
433
457
458
+ Assert (MyProcSignalSlot );
459
+
434
460
/* Exit quickly if there's no work to do. */
435
461
if (!ProcSignalBarrierPending )
436
462
return ;
437
463
ProcSignalBarrierPending = false;
438
464
439
465
/*
440
- * Read the current barrier generation, and then get the flags that are
441
- * set for this backend. Note that pg_atomic_exchange_u32 is a full
442
- * barrier, so we're guaranteed that the read of the barrier generation
443
- * happens before we atomically extract the flags, and that any subsequent
444
- * state changes happen afterward.
466
+ * It's not unlikely to process multiple barriers at once, before the
467
+ * signals for all the barriers have arrived. To avoid unnecessary work in
468
+ * response to subsequent signals, exit early if we already have processed
469
+ * all of them.
470
+ */
471
+ local_gen = pg_atomic_read_u64 (& MyProcSignalSlot -> pss_barrierGeneration );
472
+ shared_gen = pg_atomic_read_u64 (& ProcSignal -> psh_barrierGeneration );
473
+
474
+ Assert (local_gen <= shared_gen );
475
+
476
+ if (local_gen == shared_gen )
477
+ return ;
478
+
479
+ /*
480
+ * Get and clear the flags that are set for this backend. Note that
481
+ * pg_atomic_exchange_u32 is a full barrier, so we're guaranteed that the
482
+ * read of the barrier generation above happens before we atomically
483
+ * extract the flags, and that any subsequent state changes happen
484
+ * afterward.
445
485
*/
446
- generation = pg_atomic_read_u64 (& ProcSignal -> psh_barrierGeneration );
447
486
flags = pg_atomic_exchange_u32 (& MyProcSignalSlot -> pss_barrierCheckMask , 0 );
448
487
449
488
/*
@@ -466,7 +505,7 @@ ProcessProcSignalBarrier(void)
466
505
* things have changed further, it'll get fixed up when this function is
467
506
* next called.
468
507
*/
469
- pg_atomic_write_u64 (& MyProcSignalSlot -> pss_barrierGeneration , generation );
508
+ pg_atomic_write_u64 (& MyProcSignalSlot -> pss_barrierGeneration , shared_gen );
470
509
}
471
510
472
511
static void
@@ -505,27 +544,6 @@ CheckProcSignal(ProcSignalReason reason)
505
544
return false;
506
545
}
507
546
508
- /*
509
- * CheckProcSignalBarrier - check for new barriers we need to absorb
510
- */
511
- static bool
512
- CheckProcSignalBarrier (void )
513
- {
514
- volatile ProcSignalSlot * slot = MyProcSignalSlot ;
515
-
516
- if (slot != NULL )
517
- {
518
- uint64 mygen ;
519
- uint64 curgen ;
520
-
521
- mygen = pg_atomic_read_u64 (& slot -> pss_barrierGeneration );
522
- curgen = pg_atomic_read_u64 (& ProcSignal -> psh_barrierGeneration );
523
- return (mygen != curgen );
524
- }
525
-
526
- return false;
527
- }
528
-
529
547
/*
530
548
* procsignal_sigusr1_handler - handle SIGUSR1 signal.
531
549
*/
@@ -546,6 +564,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
546
564
if (CheckProcSignal (PROCSIG_WALSND_INIT_STOPPING ))
547
565
HandleWalSndInitStopping ();
548
566
567
+ if (CheckProcSignal (PROCSIG_BARRIER ))
568
+ HandleProcSignalBarrierInterrupt ();
569
+
549
570
if (CheckProcSignal (PROCSIG_RECOVERY_CONFLICT_DATABASE ))
550
571
RecoveryConflictInterrupt (PROCSIG_RECOVERY_CONFLICT_DATABASE );
551
572
@@ -564,12 +585,6 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
564
585
if (CheckProcSignal (PROCSIG_RECOVERY_CONFLICT_BUFFERPIN ))
565
586
RecoveryConflictInterrupt (PROCSIG_RECOVERY_CONFLICT_BUFFERPIN );
566
587
567
- if (CheckProcSignalBarrier ())
568
- {
569
- InterruptPending = true;
570
- ProcSignalBarrierPending = true;
571
- }
572
-
573
588
SetLatch (MyLatch );
574
589
575
590
latch_sigusr1_handler ();
0 commit comments