PostgreSQL Source Code git master
Loading...
Searching...
No Matches
procsignal.c File Reference
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include "access/parallel.h"
#include "commands/async.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_bitutils.h"
#include "replication/logicalworker.h"
#include "replication/walsender.h"
#include "storage/condition_variable.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/shmem.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
Include dependency graph for procsignal.c:

Go to the source code of this file.

Data Structures

struct  ProcSignalSlot
 
struct  ProcSignalHeader
 

Macros

#define NumProcSignalSlots   (MaxBackends + NUM_AUXILIARY_PROCS)
 
#define BARRIER_SHOULD_CHECK(flags, type)    (((flags) & (((uint32) 1) << (uint32) (type))) != 0)
 
#define BARRIER_CLEAR_BIT(flags, type)    ((flags) &= ~(((uint32) 1) << (uint32) (type)))
 

Functions

static bool CheckProcSignal (ProcSignalReason reason)
 
static void CleanupProcSignalState (int status, Datum arg)
 
static void ResetProcSignalBarrierBits (uint32 flags)
 
Size ProcSignalShmemSize (void)
 
void ProcSignalShmemInit (void)
 
void ProcSignalInit (const uint8 *cancel_key, int cancel_key_len)
 
int SendProcSignal (pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
 
uint64 EmitProcSignalBarrier (ProcSignalBarrierType type)
 
void WaitForProcSignalBarrier (uint64 generation)
 
static void HandleProcSignalBarrierInterrupt (void)
 
void ProcessProcSignalBarrier (void)
 
void procsignal_sigusr1_handler (SIGNAL_ARGS)
 
void SendCancelRequest (int backendPID, const uint8 *cancel_key, int cancel_key_len)
 

Variables

NON_EXEC_STATIC ProcSignalHeaderProcSignal = NULL
 
static ProcSignalSlotMyProcSignalSlot = NULL
 

Macro Definition Documentation

◆ BARRIER_CLEAR_BIT

#define BARRIER_CLEAR_BIT (   flags,
  type 
)     ((flags) &= ~(((uint32) 1) << (uint32) (type)))

Definition at line 102 of file procsignal.c.

117{
118 Size size;
119
121 size = add_size(size, offsetof(ProcSignalHeader, psh_slot));
122 return size;
123}
124
125/*
126 * ProcSignalShmemInit
127 * Allocate and initialize ProcSignal's shared memory
128 */
129void
131{
132 Size size = ProcSignalShmemSize();
133 bool found;
134
136 ShmemInitStruct("ProcSignal", size, &found);
137
138 /* If we're first, initialize. */
139 if (!found)
140 {
141 int i;
142
144
145 for (i = 0; i < NumProcSignalSlots; ++i)
146 {
148
149 SpinLockInit(&slot->pss_mutex);
150 pg_atomic_init_u32(&slot->pss_pid, 0);
151 slot->pss_cancel_key_len = 0;
152 MemSet(slot->pss_signalFlags, 0, sizeof(slot->pss_signalFlags));
156 }
157 }
158}
159
160/*
161 * ProcSignalInit
162 * Register the current process in the ProcSignal array
163 */
164void
166{
167 ProcSignalSlot *slot;
170
172 if (MyProcNumber < 0)
173 elog(ERROR, "MyProcNumber not set");
175 elog(ERROR, "unexpected MyProcNumber %d in ProcSignalInit (max %d)", MyProcNumber, NumProcSignalSlots);
177
179
180 /* Value used for sanity check below */
182
183 /* Clear out any leftover signal reasons */
185
186 /*
187 * Initialize barrier state. Since we're a brand-new process, there
188 * shouldn't be any leftover backend-private state that needs to be
189 * updated. Therefore, we can broadcast the latest barrier generation and
190 * disregard any previously-set check bits.
191 *
192 * NB: This only works if this initialization happens early enough in the
193 * startup sequence that we haven't yet cached any state that might need
194 * to be invalidated. That's also why we have a memory barrier here, to be
195 * sure that any later reads of memory happen strictly after this.
196 */
201
202 if (cancel_key_len > 0)
206
208
209 /* Spinlock is released, do the check */
210 if (old_pss_pid != 0)
211 elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
213
214 /* Remember slot location for CheckProcSignal */
215 MyProcSignalSlot = slot;
216
217 /* Set up to release the slot on process exit */
219}
220
221/*
222 * CleanupProcSignalState
223 * Remove current process from ProcSignal mechanism
224 *
225 * This function is called via on_shmem_exit() during backend shutdown.
226 */
227static void
229{
232
233 /*
234 * Clear MyProcSignalSlot, so that a SIGUSR1 received after this point
235 * won't try to access it after it's no longer ours (and perhaps even
236 * after we've unmapped the shared memory segment).
237 */
240
241 /* sanity check */
244 if (old_pid != MyProcPid)
245 {
246 /*
247 * don't ERROR here. We're exiting anyway, and don't want to get into
248 * infinite loop trying to exit
249 */
251 elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d",
252 MyProcPid, (int) (slot - ProcSignal->psh_slot), (int) old_pid);
253 return; /* XXX better to zero the slot anyway? */
254 }
255
256 /* Mark the slot as unused */
257 pg_atomic_write_u32(&slot->pss_pid, 0);
258 slot->pss_cancel_key_len = 0;
259
260 /*
261 * Make this slot look like it's absorbed all possible barriers, so that
262 * no barrier waits block on it.
263 */
265
267
269}
270
271/*
272 * SendProcSignal
273 * Send a signal to a Postgres process
274 *
275 * Providing procNumber is optional, but it will speed up the operation.
276 *
277 * On success (a signal was sent), zero is returned.
278 * On error, -1 is returned, and errno is set (typically to ESRCH or EPERM).
279 *
280 * Not to be confused with ProcSendSignal
281 */
282int
283SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
284{
285 volatile ProcSignalSlot *slot;
286
287 if (procNumber != INVALID_PROC_NUMBER)
288 {
289 Assert(procNumber < NumProcSignalSlots);
290 slot = &ProcSignal->psh_slot[procNumber];
291
293 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
294 {
295 /* Atomically set the proper flag */
296 slot->pss_signalFlags[reason] = true;
298 /* Send signal */
299 return kill(pid, SIGUSR1);
300 }
302 }
303 else
304 {
305 /*
306 * procNumber not provided, so search the array using pid. We search
307 * the array back to front so as to reduce search overhead. Passing
308 * INVALID_PROC_NUMBER means that the target is most likely an
309 * auxiliary process, which will have a slot near the end of the
310 * array.
311 */
312 int i;
313
314 for (i = NumProcSignalSlots - 1; i >= 0; i--)
315 {
316 slot = &ProcSignal->psh_slot[i];
317
318 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
319 {
321 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
322 {
323 /* Atomically set the proper flag */
324 slot->pss_signalFlags[reason] = true;
326 /* Send signal */
327 return kill(pid, SIGUSR1);
328 }
330 }
331 }
332 }
333
334 errno = ESRCH;
335 return -1;
336}
337
338/*
339 * EmitProcSignalBarrier
340 * Send a signal to every Postgres process
341 *
342 * The return value of this function is the barrier "generation" created
343 * by this operation. This value can be passed to WaitForProcSignalBarrier
344 * to wait until it is known that every participant in the ProcSignal
345 * mechanism has absorbed the signal (or started afterwards).
346 *
347 * Note that it would be a bad idea to use this for anything that happens
348 * frequently, as interrupting every backend could cause a noticeable
349 * performance hit.
350 *
351 * Callers are entitled to assume that this function will not throw ERROR
352 * or FATAL.
353 */
354uint64
356{
357 uint32 flagbit = 1 << (uint32) type;
358 uint64 generation;
359
360 /*
361 * Set all the flags.
362 *
363 * Note that pg_atomic_fetch_or_u32 has full barrier semantics, so this is
364 * totally ordered with respect to anything the caller did before, and
365 * anything that we do afterwards. (This is also true of the later call to
366 * pg_atomic_add_fetch_u64.)
367 */
368 for (int i = 0; i < NumProcSignalSlots; i++)
369 {
370 volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
371
373 }
374
375 /*
376 * Increment the generation counter.
377 */
378 generation =
380
381 /*
382 * Signal all the processes, so that they update their advertised barrier
383 * generation.
384 *
385 * Concurrency is not a problem here. Backends that have exited don't
386 * matter, and new backends that have joined since we entered this
387 * function must already have current state, since the caller is
388 * responsible for making sure that the relevant state is entirely visible
389 * before calling this function in the first place. We still have to wake
390 * them up - because we can't distinguish between such backends and older
391 * backends that need to update state - but they won't actually need to
392 * change any state.
393 */
394 for (int i = NumProcSignalSlots - 1; i >= 0; i--)
395 {
396 volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
397 pid_t pid = pg_atomic_read_u32(&slot->pss_pid);
398
399 if (pid != 0)
400 {
402 pid = pg_atomic_read_u32(&slot->pss_pid);
403 if (pid != 0)
404 {
405 /* see SendProcSignal for details */
406 slot->pss_signalFlags[PROCSIG_BARRIER] = true;
408 kill(pid, SIGUSR1);
409 }
410 else
412 }
413 }
414
415 return generation;
416}
417
418/*
419 * WaitForProcSignalBarrier - wait until it is guaranteed that all changes
420 * requested by a specific call to EmitProcSignalBarrier() have taken effect.
421 */
422void
424{
426
427 elog(DEBUG1,
428 "waiting for all backends to process ProcSignalBarrier generation "
430 generation);
431
432 for (int i = NumProcSignalSlots - 1; i >= 0; i--)
433 {
436
437 /*
438 * It's important that we check only pss_barrierGeneration here and
439 * not pss_barrierCheckMask. Bits in pss_barrierCheckMask get cleared
440 * before the barrier is actually absorbed, but pss_barrierGeneration
441 * is updated only afterward.
442 */
444 while (oldval < generation)
445 {
447 5000,
449 ereport(LOG,
450 (errmsg("still waiting for backend with PID %d to accept ProcSignalBarrier",
451 (int) pg_atomic_read_u32(&slot->pss_pid))));
453 }
455 }
456
457 elog(DEBUG1,
458 "finished waiting for all backends to process ProcSignalBarrier generation "
460 generation);
461
462 /*
463 * The caller is probably calling this function because it wants to read
464 * the shared state or perform further writes to shared state once all
465 * backends are known to have absorbed the barrier. However, the read of
466 * pss_barrierGeneration was performed unlocked; insert a memory barrier
467 * to separate it from whatever follows.
468 */
470}
471
472/*
473 * Handle receipt of an interrupt indicating a global barrier event.
474 *
475 * All the actual work is deferred to ProcessProcSignalBarrier(), because we
476 * cannot safely access the barrier generation inside the signal handler as
477 * 64bit atomics might use spinlock based emulation, even for reads. As this
478 * routine only gets called when PROCSIG_BARRIER is sent that won't cause a
479 * lot of unnecessary work.
480 */
481static void
483{
484 InterruptPending = true;
486 /* latch will be set by procsignal_sigusr1_handler */
487}
488
489/*
490 * Perform global barrier related interrupt checking.
491 *
492 * Any backend that participates in ProcSignal signaling must arrange to
493 * call this function periodically. It is called from CHECK_FOR_INTERRUPTS(),
494 * which is enough for normal backends, but not necessarily for all types of
495 * background processes.
496 */
497void
499{
502 volatile uint32 flags;
503
505
506 /* Exit quickly if there's no work to do. */
508 return;
510
511 /*
512 * It's not unlikely to process multiple barriers at once, before the
513 * signals for all the barriers have arrived. To avoid unnecessary work in
514 * response to subsequent signals, exit early if we already have processed
515 * all of them.
516 */
519
521
522 if (local_gen == shared_gen)
523 return;
524
525 /*
526 * Get and clear the flags that are set for this backend. Note that
527 * pg_atomic_exchange_u32 is a full barrier, so we're guaranteed that the
528 * read of the barrier generation above happens before we atomically
529 * extract the flags, and that any subsequent state changes happen
530 * afterward.
531 *
532 * NB: In order to avoid race conditions, we must zero
533 * pss_barrierCheckMask first and only afterwards try to do barrier
534 * processing. If we did it in the other order, someone could send us
535 * another barrier of some type right after we called the
536 * barrier-processing function but before we cleared the bit. We would
537 * have no way of knowing that the bit needs to stay set in that case, so
538 * the need to call the barrier-processing function again would just get
539 * forgotten. So instead, we tentatively clear all the bits and then put
540 * back any for which we don't manage to successfully absorb the barrier.
541 */
543
544 /*
545 * If there are no flags set, then we can skip doing any real work.
546 * Otherwise, establish a PG_TRY block, so that we don't lose track of
547 * which types of barrier processing are needed if an ERROR occurs.
548 */
549 if (flags != 0)
550 {
551 bool success = true;
552
553 PG_TRY();
554 {
555 /*
556 * Process each type of barrier. The barrier-processing functions
557 * should normally return true, but may return false if the
558 * barrier can't be absorbed at the current time. This should be
559 * rare, because it's pretty expensive. Every single
560 * CHECK_FOR_INTERRUPTS() will return here until we manage to
561 * absorb the barrier, and that cost will add up in a hurry.
562 *
563 * NB: It ought to be OK to call the barrier-processing functions
564 * unconditionally, but it's more efficient to call only the ones
565 * that might need us to do something based on the flags.
566 */
567 while (flags != 0)
568 {
570 bool processed = true;
571
573 switch (type)
574 {
576 processed = ProcessBarrierSmgrRelease();
577 break;
580 break;
581 }
582
583 /*
584 * To avoid an infinite loop, we must always unset the bit in
585 * flags.
586 */
587 BARRIER_CLEAR_BIT(flags, type);
588
589 /*
590 * If we failed to process the barrier, reset the shared bit
591 * so we try again later, and set a flag so that we don't bump
592 * our generation.
593 */
594 if (!processed)
595 {
597 success = false;
598 }
599 }
600 }
601 PG_CATCH();
602 {
603 /*
604 * If an ERROR occurred, we'll need to try again later to handle
605 * that barrier type and any others that haven't been handled yet
606 * or weren't successfully absorbed.
607 */
609 PG_RE_THROW();
610 }
611 PG_END_TRY();
612
613 /*
614 * If some barrier types were not successfully absorbed, we will have
615 * to try again later.
616 */
617 if (!success)
618 return;
619 }
620
621 /*
622 * State changes related to all types of barriers that might have been
623 * emitted have now been handled, so we can update our notion of the
624 * generation to the one we observed before beginning the updates. If
625 * things have changed further, it'll get fixed up when this function is
626 * next called.
627 */
630}
631
632/*
633 * If it turns out that we couldn't absorb one or more barrier types, either
634 * because the barrier-processing functions returned false or due to an error,
635 * arrange for processing to be retried later.
636 */
637static void
639{
642 InterruptPending = true;
643}
644
645/*
646 * CheckProcSignal - check to see if a particular reason has been
647 * signaled, and clear the signal flag. Should be called after receiving
648 * SIGUSR1.
649 */
650static bool
652{
653 volatile ProcSignalSlot *slot = MyProcSignalSlot;
654
655 if (slot != NULL)
656 {
657 /*
658 * Careful here --- don't clear flag if we haven't seen it set.
659 * pss_signalFlags is of type "volatile sig_atomic_t" to allow us to
660 * read it here safely, without holding the spinlock.
661 */
662 if (slot->pss_signalFlags[reason])
663 {
664 slot->pss_signalFlags[reason] = false;
665 return true;
666 }
667 }
668
669 return false;
670}
671
672/*
673 * procsignal_sigusr1_handler - handle SIGUSR1 signal.
674 */
675void
677{
680
683
686
689
692
695
698
701
704
707
710
713
716
719
721}
722
723/*
724 * Send a query cancellation signal to backend.
725 *
726 * Note: This is called from a backend process before authentication. We
727 * cannot take LWLocks yet, but that's OK; we rely on atomic reads of the
728 * fields in the ProcSignal slots.
729 */
730void
731SendCancelRequest(int backendPID, const uint8 *cancel_key, int cancel_key_len)
732{
733 if (backendPID == 0)
734 {
735 ereport(LOG, (errmsg("invalid cancel request with PID 0")));
736 return;
737 }
738
739 /*
740 * See if we have a matching backend. Reading the pss_pid and
741 * pss_cancel_key fields is racy, a backend might die and remove itself
742 * from the array at any time. The probability of the cancellation key
743 * matching wrong process is miniscule, however, so we can live with that.
744 * PIDs are reused too, so sending the signal based on PID is inherently
745 * racy anyway, although OS's avoid reusing PIDs too soon.
746 */
747 for (int i = 0; i < NumProcSignalSlots; i++)
748 {
750 bool match;
751
752 if (pg_atomic_read_u32(&slot->pss_pid) != backendPID)
753 continue;
754
755 /* Acquire the spinlock and re-check */
757 if (pg_atomic_read_u32(&slot->pss_pid) != backendPID)
758 {
760 continue;
761 }
762 else
763 {
764 match = slot->pss_cancel_key_len == cancel_key_len &&
766
768
769 if (match)
770 {
771 /* Found a match; signal that backend to cancel current op */
773 (errmsg_internal("processing cancel request: sending SIGINT to process %d",
774 backendPID)));
775
776 /*
777 * If we have setsid(), signal the backend's whole process
778 * group
779 */
780#ifdef HAVE_SETSID
781 kill(-backendPID, SIGINT);
782#else
783 kill(backendPID, SIGINT);
784#endif
785 }
786 else
787 {
788 /* Right PID, wrong key: no way, Jose */
789 ereport(LOG,
790 (errmsg("wrong key in cancel request for process %d",
791 backendPID)));
792 }
793 return;
794 }
795 }
796
797 /* No matching backend */
798 ereport(LOG,
799 (errmsg("PID %d in cancel request did not match any process",
800 backendPID)));
801}
void HandleParallelApplyMessageInterrupt(void)
void HandleNotifyInterrupt(void)
Definition async.c:2542
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:485
static uint32 pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
Definition atomics.h:410
#define pg_memory_barrier()
Definition atomics.h:141
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition atomics.h:219
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition atomics.h:274
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition atomics.h:237
static uint64 pg_atomic_add_fetch_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
Definition atomics.h:569
static uint32 pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
Definition atomics.h:330
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:453
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:467
void HandleParallelMessageInterrupt(void)
Definition parallel.c:1044
uint8_t uint8
Definition c.h:544
#define SIGNAL_ARGS
Definition c.h:1357
#define Assert(condition)
Definition c.h:873
#define UINT64_FORMAT
Definition c.h:565
uint64_t uint64
Definition c.h:547
uint32_t uint32
Definition c.h:546
#define PG_UINT64_MAX
Definition c.h:607
#define MemSet(start, val, len)
Definition c.h:1013
size_t Size
Definition c.h:619
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
void ConditionVariableBroadcast(ConditionVariable *cv)
void ConditionVariableInit(ConditionVariable *cv)
int errmsg_internal(const char *fmt,...)
Definition elog.c:1170
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define LOG
Definition elog.h:31
#define PG_RE_THROW()
Definition elog.h:405
#define PG_TRY(...)
Definition elog.h:372
#define DEBUG2
Definition elog.h:29
#define PG_END_TRY(...)
Definition elog.h:397
#define DEBUG1
Definition elog.h:30
#define ERROR
Definition elog.h:39
#define PG_CATCH(...)
Definition elog.h:382
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
volatile sig_atomic_t ProcSignalBarrierPending
Definition globals.c:40
volatile sig_atomic_t InterruptPending
Definition globals.c:32
int MyProcPid
Definition globals.c:47
ProcNumber MyProcNumber
Definition globals.c:90
struct Latch * MyLatch
Definition globals.c:63
static bool success
Definition initdb.c:187
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
int i
Definition isn.c:77
void SetLatch(Latch *latch)
Definition latch.c:290
bool ProcessBarrierUpdateXLogLogicalInfo(void)
Definition logicalctl.c:186
void HandleLogMemoryContextInterrupt(void)
Definition mcxt.c:1323
void * arg
static int pg_rightmost_one_pos32(uint32 word)
int timingsafe_bcmp(const void *b1, const void *b2, size_t n)
void HandleRecoveryConflictInterrupt(ProcSignalReason reason)
Definition postgres.c:3095
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
int ProcNumber
Definition procnumber.h:24
static void CleanupProcSignalState(int status, Datum arg)
Definition procsignal.c:229
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition procsignal.c:284
void ProcSignalInit(const uint8 *cancel_key, int cancel_key_len)
Definition procsignal.c:166
void ProcSignalShmemInit(void)
Definition procsignal.c:131
#define NumProcSignalSlots
Definition procsignal.c:95
static bool CheckProcSignal(ProcSignalReason reason)
Definition procsignal.c:652
void ProcessProcSignalBarrier(void)
Definition procsignal.c:499
void WaitForProcSignalBarrier(uint64 generation)
Definition procsignal.c:424
NON_EXEC_STATIC ProcSignalHeader * ProcSignal
Definition procsignal.c:105
static void ResetProcSignalBarrierBits(uint32 flags)
Definition procsignal.c:639
void SendCancelRequest(int backendPID, const uint8 *cancel_key, int cancel_key_len)
Definition procsignal.c:732
uint64 EmitProcSignalBarrier(ProcSignalBarrierType type)
Definition procsignal.c:356
Size ProcSignalShmemSize(void)
Definition procsignal.c:117
static void HandleProcSignalBarrierInterrupt(void)
Definition procsignal.c:483
static ProcSignalSlot * MyProcSignalSlot
Definition procsignal.c:106
#define BARRIER_CLEAR_BIT(flags, type)
Definition procsignal.c:102
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition procsignal.c:677
#define NUM_PROCSIGNALS
Definition procsignal.h:52
ProcSignalReason
Definition procsignal.h:31
@ PROCSIG_PARALLEL_MESSAGE
Definition procsignal.h:34
@ PROCSIG_RECOVERY_CONFLICT_BUFFERPIN
Definition procsignal.h:47
@ PROCSIG_CATCHUP_INTERRUPT
Definition procsignal.h:32
@ PROCSIG_RECOVERY_CONFLICT_LOCK
Definition procsignal.h:44
@ PROCSIG_LOG_MEMORY_CONTEXT
Definition procsignal.h:37
@ PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT
Definition procsignal.h:46
@ PROCSIG_BARRIER
Definition procsignal.h:36
@ PROCSIG_RECOVERY_CONFLICT_DATABASE
Definition procsignal.h:42
@ PROCSIG_WALSND_INIT_STOPPING
Definition procsignal.h:35
@ PROCSIG_PARALLEL_APPLY_MESSAGE
Definition procsignal.h:38
@ PROCSIG_RECOVERY_CONFLICT_SNAPSHOT
Definition procsignal.h:45
@ PROCSIG_NOTIFY_INTERRUPT
Definition procsignal.h:33
@ PROCSIG_RECOVERY_CONFLICT_TABLESPACE
Definition procsignal.h:43
@ PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition procsignal.h:48
ProcSignalBarrierType
Definition procsignal.h:55
@ PROCSIGNAL_BARRIER_SMGRRELEASE
Definition procsignal.h:56
@ PROCSIGNAL_BARRIER_UPDATE_XLOG_LOGICAL_INFO
Definition procsignal.h:57
#define MAX_CANCEL_KEY_LENGTH
Definition procsignal.h:69
Size add_size(Size s1, Size s2)
Definition shmem.c:495
Size mul_size(Size s1, Size s2)
Definition shmem.c:510
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:389
void HandleCatchupInterrupt(void)
Definition sinval.c:154
bool ProcessBarrierSmgrRelease(void)
Definition smgr.c:1027
#define SpinLockInit(lock)
Definition spin.h:57
#define SpinLockRelease(lock)
Definition spin.h:61
#define SpinLockAcquire(lock)
Definition spin.h:59
ProcSignalSlot psh_slot[FLEXIBLE_ARRAY_MEMBER]
Definition procsignal.c:86
pg_atomic_uint64 psh_barrierGeneration
Definition procsignal.c:85
uint8 pss_cancel_key[MAX_CANCEL_KEY_LENGTH]
Definition procsignal.c:67
ConditionVariable pss_barrierCV
Definition procsignal.c:74
pg_atomic_uint64 pss_barrierGeneration
Definition procsignal.c:72
volatile sig_atomic_t pss_signalFlags[NUM_PROCSIGNALS]
Definition procsignal.c:68
slock_t pss_mutex
Definition procsignal.c:69
pg_atomic_uint32 pss_pid
Definition procsignal.c:65
int pss_cancel_key_len
Definition procsignal.c:66
pg_atomic_uint32 pss_barrierCheckMask
Definition procsignal.c:73
const char * type
void HandleWalSndInitStopping(void)
Definition walsender.c:3693
#define kill(pid, sig)
Definition win32_port.h:490
#define SIGUSR1
Definition win32_port.h:170

◆ BARRIER_SHOULD_CHECK

#define BARRIER_SHOULD_CHECK (   flags,
  type 
)     (((flags) & (((uint32) 1) << (uint32) (type))) != 0)

Definition at line 98 of file procsignal.c.

◆ NumProcSignalSlots

#define NumProcSignalSlots   (MaxBackends + NUM_AUXILIARY_PROCS)

Definition at line 95 of file procsignal.c.

Function Documentation

◆ CheckProcSignal()

static bool CheckProcSignal ( ProcSignalReason  reason)
static

Definition at line 652 of file procsignal.c.

653{
654 volatile ProcSignalSlot *slot = MyProcSignalSlot;
655
656 if (slot != NULL)
657 {
658 /*
659 * Careful here --- don't clear flag if we haven't seen it set.
660 * pss_signalFlags is of type "volatile sig_atomic_t" to allow us to
661 * read it here safely, without holding the spinlock.
662 */
663 if (slot->pss_signalFlags[reason])
664 {
665 slot->pss_signalFlags[reason] = false;
666 return true;
667 }
668 }
669
670 return false;
671}

References fb(), MyProcSignalSlot, and ProcSignalSlot::pss_signalFlags.

Referenced by procsignal_sigusr1_handler().

◆ CleanupProcSignalState()

static void CleanupProcSignalState ( int  status,
Datum  arg 
)
static

Definition at line 229 of file procsignal.c.

230{
233
234 /*
235 * Clear MyProcSignalSlot, so that a SIGUSR1 received after this point
236 * won't try to access it after it's no longer ours (and perhaps even
237 * after we've unmapped the shared memory segment).
238 */
241
242 /* sanity check */
245 if (old_pid != MyProcPid)
246 {
247 /*
248 * don't ERROR here. We're exiting anyway, and don't want to get into
249 * infinite loop trying to exit
250 */
252 elog(LOG, "process %d releasing ProcSignal slot %d, but it contains %d",
253 MyProcPid, (int) (slot - ProcSignal->psh_slot), (int) old_pid);
254 return; /* XXX better to zero the slot anyway? */
255 }
256
257 /* Mark the slot as unused */
258 pg_atomic_write_u32(&slot->pss_pid, 0);
259 slot->pss_cancel_key_len = 0;
260
261 /*
262 * Make this slot look like it's absorbed all possible barriers, so that
263 * no barrier waits block on it.
264 */
266
268
270}

References Assert, ConditionVariableBroadcast(), elog, fb(), LOG, MyProcPid, MyProcSignalSlot, pg_atomic_read_u32(), pg_atomic_write_u32(), pg_atomic_write_u64(), PG_UINT64_MAX, ProcSignal, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_barrierCV, ProcSignalSlot::pss_barrierGeneration, ProcSignalSlot::pss_cancel_key_len, ProcSignalSlot::pss_mutex, ProcSignalSlot::pss_pid, SpinLockAcquire, and SpinLockRelease.

Referenced by ProcSignalInit().

◆ EmitProcSignalBarrier()

uint64 EmitProcSignalBarrier ( ProcSignalBarrierType  type)

Definition at line 356 of file procsignal.c.

357{
358 uint32 flagbit = 1 << (uint32) type;
359 uint64 generation;
360
361 /*
362 * Set all the flags.
363 *
364 * Note that pg_atomic_fetch_or_u32 has full barrier semantics, so this is
365 * totally ordered with respect to anything the caller did before, and
366 * anything that we do afterwards. (This is also true of the later call to
367 * pg_atomic_add_fetch_u64.)
368 */
369 for (int i = 0; i < NumProcSignalSlots; i++)
370 {
371 volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
372
374 }
375
376 /*
377 * Increment the generation counter.
378 */
379 generation =
381
382 /*
383 * Signal all the processes, so that they update their advertised barrier
384 * generation.
385 *
386 * Concurrency is not a problem here. Backends that have exited don't
387 * matter, and new backends that have joined since we entered this
388 * function must already have current state, since the caller is
389 * responsible for making sure that the relevant state is entirely visible
390 * before calling this function in the first place. We still have to wake
391 * them up - because we can't distinguish between such backends and older
392 * backends that need to update state - but they won't actually need to
393 * change any state.
394 */
395 for (int i = NumProcSignalSlots - 1; i >= 0; i--)
396 {
397 volatile ProcSignalSlot *slot = &ProcSignal->psh_slot[i];
398 pid_t pid = pg_atomic_read_u32(&slot->pss_pid);
399
400 if (pid != 0)
401 {
403 pid = pg_atomic_read_u32(&slot->pss_pid);
404 if (pid != 0)
405 {
406 /* see SendProcSignal for details */
407 slot->pss_signalFlags[PROCSIG_BARRIER] = true;
409 kill(pid, SIGUSR1);
410 }
411 else
413 }
414 }
415
416 return generation;
417}

References fb(), i, kill, NumProcSignalSlots, pg_atomic_add_fetch_u64(), pg_atomic_fetch_or_u32(), pg_atomic_read_u32(), PROCSIG_BARRIER, ProcSignal, ProcSignalHeader::psh_barrierGeneration, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_barrierCheckMask, ProcSignalSlot::pss_mutex, ProcSignalSlot::pss_pid, ProcSignalSlot::pss_signalFlags, SIGUSR1, SpinLockAcquire, SpinLockRelease, and type.

Referenced by abort_logical_decoding_activation(), dbase_redo(), DisableLogicalDecoding(), dropdb(), DropTableSpace(), EnableLogicalDecoding(), movedb(), tblspc_redo(), and UpdateLogicalDecodingStatusEndOfRecovery().

◆ HandleProcSignalBarrierInterrupt()

static void HandleProcSignalBarrierInterrupt ( void  )
static

Definition at line 483 of file procsignal.c.

484{
485 InterruptPending = true;
487 /* latch will be set by procsignal_sigusr1_handler */
488}

References InterruptPending, and ProcSignalBarrierPending.

Referenced by procsignal_sigusr1_handler().

◆ ProcessProcSignalBarrier()

void ProcessProcSignalBarrier ( void  )

Definition at line 499 of file procsignal.c.

500{
503 volatile uint32 flags;
504
506
507 /* Exit quickly if there's no work to do. */
509 return;
511
512 /*
513 * It's not unlikely to process multiple barriers at once, before the
514 * signals for all the barriers have arrived. To avoid unnecessary work in
515 * response to subsequent signals, exit early if we already have processed
516 * all of them.
517 */
520
522
523 if (local_gen == shared_gen)
524 return;
525
526 /*
527 * Get and clear the flags that are set for this backend. Note that
528 * pg_atomic_exchange_u32 is a full barrier, so we're guaranteed that the
529 * read of the barrier generation above happens before we atomically
530 * extract the flags, and that any subsequent state changes happen
531 * afterward.
532 *
533 * NB: In order to avoid race conditions, we must zero
534 * pss_barrierCheckMask first and only afterwards try to do barrier
535 * processing. If we did it in the other order, someone could send us
536 * another barrier of some type right after we called the
537 * barrier-processing function but before we cleared the bit. We would
538 * have no way of knowing that the bit needs to stay set in that case, so
539 * the need to call the barrier-processing function again would just get
540 * forgotten. So instead, we tentatively clear all the bits and then put
541 * back any for which we don't manage to successfully absorb the barrier.
542 */
544
545 /*
546 * If there are no flags set, then we can skip doing any real work.
547 * Otherwise, establish a PG_TRY block, so that we don't lose track of
548 * which types of barrier processing are needed if an ERROR occurs.
549 */
550 if (flags != 0)
551 {
552 bool success = true;
553
554 PG_TRY();
555 {
556 /*
557 * Process each type of barrier. The barrier-processing functions
558 * should normally return true, but may return false if the
559 * barrier can't be absorbed at the current time. This should be
560 * rare, because it's pretty expensive. Every single
561 * CHECK_FOR_INTERRUPTS() will return here until we manage to
562 * absorb the barrier, and that cost will add up in a hurry.
563 *
564 * NB: It ought to be OK to call the barrier-processing functions
565 * unconditionally, but it's more efficient to call only the ones
566 * that might need us to do something based on the flags.
567 */
568 while (flags != 0)
569 {
571 bool processed = true;
572
574 switch (type)
575 {
577 processed = ProcessBarrierSmgrRelease();
578 break;
581 break;
582 }
583
584 /*
585 * To avoid an infinite loop, we must always unset the bit in
586 * flags.
587 */
588 BARRIER_CLEAR_BIT(flags, type);
589
590 /*
591 * If we failed to process the barrier, reset the shared bit
592 * so we try again later, and set a flag so that we don't bump
593 * our generation.
594 */
595 if (!processed)
596 {
598 success = false;
599 }
600 }
601 }
602 PG_CATCH();
603 {
604 /*
605 * If an ERROR occurred, we'll need to try again later to handle
606 * that barrier type and any others that haven't been handled yet
607 * or weren't successfully absorbed.
608 */
610 PG_RE_THROW();
611 }
612 PG_END_TRY();
613
614 /*
615 * If some barrier types were not successfully absorbed, we will have
616 * to try again later.
617 */
618 if (!success)
619 return;
620 }
621
622 /*
623 * State changes related to all types of barriers that might have been
624 * emitted have now been handled, so we can update our notion of the
625 * generation to the one we observed before beginning the updates. If
626 * things have changed further, it'll get fixed up when this function is
627 * next called.
628 */
631}

References Assert, BARRIER_CLEAR_BIT, ConditionVariableBroadcast(), fb(), MyProcSignalSlot, pg_atomic_exchange_u32(), pg_atomic_read_u64(), pg_atomic_write_u64(), PG_CATCH, PG_END_TRY, PG_RE_THROW, pg_rightmost_one_pos32(), PG_TRY, ProcessBarrierSmgrRelease(), ProcessBarrierUpdateXLogLogicalInfo(), ProcSignal, PROCSIGNAL_BARRIER_SMGRRELEASE, PROCSIGNAL_BARRIER_UPDATE_XLOG_LOGICAL_INFO, ProcSignalBarrierPending, ProcSignalHeader::psh_barrierGeneration, ProcSignalSlot::pss_barrierCheckMask, ProcSignalSlot::pss_barrierCV, ProcSignalSlot::pss_barrierGeneration, ResetProcSignalBarrierBits(), success, and type.

Referenced by BufferSync(), CheckpointWriteDelay(), ProcessAutoVacLauncherInterrupts(), ProcessCheckpointerInterrupts(), ProcessInterrupts(), ProcessMainLoopInterrupts(), ProcessPgArchInterrupts(), ProcessStartupProcInterrupts(), and ProcessWalSummarizerInterrupts().

◆ procsignal_sigusr1_handler()

void procsignal_sigusr1_handler ( SIGNAL_ARGS  )

Definition at line 677 of file procsignal.c.

678{
681
684
687
690
693
696
699
702
705
708
711
714
717
720
722}

References CheckProcSignal(), HandleCatchupInterrupt(), HandleLogMemoryContextInterrupt(), HandleNotifyInterrupt(), HandleParallelApplyMessageInterrupt(), HandleParallelMessageInterrupt(), HandleProcSignalBarrierInterrupt(), HandleRecoveryConflictInterrupt(), HandleWalSndInitStopping(), MyLatch, PROCSIG_BARRIER, PROCSIG_CATCHUP_INTERRUPT, PROCSIG_LOG_MEMORY_CONTEXT, PROCSIG_NOTIFY_INTERRUPT, PROCSIG_PARALLEL_APPLY_MESSAGE, PROCSIG_PARALLEL_MESSAGE, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_DATABASE, PROCSIG_RECOVERY_CONFLICT_LOCK, PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, PROCSIG_RECOVERY_CONFLICT_TABLESPACE, PROCSIG_WALSND_INIT_STOPPING, and SetLatch().

Referenced by autoprewarm_main(), AutoVacLauncherMain(), AutoVacWorkerMain(), BackgroundWorkerMain(), BackgroundWriterMain(), CheckpointerMain(), IoWorkerMain(), PgArchiverMain(), PostgresMain(), ReplSlotSyncWorkerMain(), StartupProcessMain(), WalReceiverMain(), WalSndSignals(), WalSummarizerMain(), and WalWriterMain().

◆ ProcSignalInit()

void ProcSignalInit ( const uint8 cancel_key,
int  cancel_key_len 
)

Definition at line 166 of file procsignal.c.

167{
168 ProcSignalSlot *slot;
171
173 if (MyProcNumber < 0)
174 elog(ERROR, "MyProcNumber not set");
176 elog(ERROR, "unexpected MyProcNumber %d in ProcSignalInit (max %d)", MyProcNumber, NumProcSignalSlots);
178
180
181 /* Value used for sanity check below */
183
184 /* Clear out any leftover signal reasons */
186
187 /*
188 * Initialize barrier state. Since we're a brand-new process, there
189 * shouldn't be any leftover backend-private state that needs to be
190 * updated. Therefore, we can broadcast the latest barrier generation and
191 * disregard any previously-set check bits.
192 *
193 * NB: This only works if this initialization happens early enough in the
194 * startup sequence that we haven't yet cached any state that might need
195 * to be invalidated. That's also why we have a memory barrier here, to be
196 * sure that any later reads of memory happen strictly after this.
197 */
202
203 if (cancel_key_len > 0)
207
209
210 /* Spinlock is released, do the check */
211 if (old_pss_pid != 0)
212 elog(LOG, "process %d taking over ProcSignal slot %d, but it's not empty",
214
215 /* Remember slot location for CheckProcSignal */
216 MyProcSignalSlot = slot;
217
218 /* Set up to release the slot on process exit */
220}

References Assert, CleanupProcSignalState(), elog, ERROR, fb(), LOG, MAX_CANCEL_KEY_LENGTH, MemSet, MyProcNumber, MyProcPid, MyProcSignalSlot, NUM_PROCSIGNALS, NumProcSignalSlots, on_shmem_exit(), pg_atomic_read_u32(), pg_atomic_read_u64(), pg_atomic_write_u32(), pg_atomic_write_u64(), ProcSignal, ProcSignalHeader::psh_barrierGeneration, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_barrierCheckMask, ProcSignalSlot::pss_barrierGeneration, ProcSignalSlot::pss_cancel_key, ProcSignalSlot::pss_cancel_key_len, ProcSignalSlot::pss_mutex, ProcSignalSlot::pss_pid, ProcSignalSlot::pss_signalFlags, SpinLockAcquire, and SpinLockRelease.

Referenced by AuxiliaryProcessMainCommon(), and InitPostgres().

◆ ProcSignalShmemInit()

◆ ProcSignalShmemSize()

Size ProcSignalShmemSize ( void  )

Definition at line 117 of file procsignal.c.

118{
119 Size size;
120
122 size = add_size(size, offsetof(ProcSignalHeader, psh_slot));
123 return size;
124}

References add_size(), fb(), mul_size(), and NumProcSignalSlots.

Referenced by CalculateShmemSize(), and ProcSignalShmemInit().

◆ ResetProcSignalBarrierBits()

◆ SendCancelRequest()

void SendCancelRequest ( int  backendPID,
const uint8 cancel_key,
int  cancel_key_len 
)

Definition at line 732 of file procsignal.c.

733{
734 if (backendPID == 0)
735 {
736 ereport(LOG, (errmsg("invalid cancel request with PID 0")));
737 return;
738 }
739
740 /*
741 * See if we have a matching backend. Reading the pss_pid and
742 * pss_cancel_key fields is racy, a backend might die and remove itself
743 * from the array at any time. The probability of the cancellation key
744 * matching wrong process is miniscule, however, so we can live with that.
745 * PIDs are reused too, so sending the signal based on PID is inherently
746 * racy anyway, although OS's avoid reusing PIDs too soon.
747 */
748 for (int i = 0; i < NumProcSignalSlots; i++)
749 {
751 bool match;
752
753 if (pg_atomic_read_u32(&slot->pss_pid) != backendPID)
754 continue;
755
756 /* Acquire the spinlock and re-check */
758 if (pg_atomic_read_u32(&slot->pss_pid) != backendPID)
759 {
761 continue;
762 }
763 else
764 {
765 match = slot->pss_cancel_key_len == cancel_key_len &&
767
769
770 if (match)
771 {
772 /* Found a match; signal that backend to cancel current op */
774 (errmsg_internal("processing cancel request: sending SIGINT to process %d",
775 backendPID)));
776
777 /*
778 * If we have setsid(), signal the backend's whole process
779 * group
780 */
781#ifdef HAVE_SETSID
782 kill(-backendPID, SIGINT);
783#else
784 kill(backendPID, SIGINT);
785#endif
786 }
787 else
788 {
789 /* Right PID, wrong key: no way, Jose */
790 ereport(LOG,
791 (errmsg("wrong key in cancel request for process %d",
792 backendPID)));
793 }
794 return;
795 }
796 }
797
798 /* No matching backend */
799 ereport(LOG,
800 (errmsg("PID %d in cancel request did not match any process",
801 backendPID)));
802}

References DEBUG2, ereport, errmsg(), errmsg_internal(), fb(), i, kill, LOG, NumProcSignalSlots, pg_atomic_read_u32(), ProcSignal, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_cancel_key, ProcSignalSlot::pss_cancel_key_len, ProcSignalSlot::pss_mutex, ProcSignalSlot::pss_pid, SpinLockAcquire, SpinLockRelease, and timingsafe_bcmp().

Referenced by ProcessCancelRequestPacket().

◆ SendProcSignal()

int SendProcSignal ( pid_t  pid,
ProcSignalReason  reason,
ProcNumber  procNumber 
)

Definition at line 284 of file procsignal.c.

285{
286 volatile ProcSignalSlot *slot;
287
288 if (procNumber != INVALID_PROC_NUMBER)
289 {
290 Assert(procNumber < NumProcSignalSlots);
291 slot = &ProcSignal->psh_slot[procNumber];
292
294 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
295 {
296 /* Atomically set the proper flag */
297 slot->pss_signalFlags[reason] = true;
299 /* Send signal */
300 return kill(pid, SIGUSR1);
301 }
303 }
304 else
305 {
306 /*
307 * procNumber not provided, so search the array using pid. We search
308 * the array back to front so as to reduce search overhead. Passing
309 * INVALID_PROC_NUMBER means that the target is most likely an
310 * auxiliary process, which will have a slot near the end of the
311 * array.
312 */
313 int i;
314
315 for (i = NumProcSignalSlots - 1; i >= 0; i--)
316 {
317 slot = &ProcSignal->psh_slot[i];
318
319 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
320 {
322 if (pg_atomic_read_u32(&slot->pss_pid) == pid)
323 {
324 /* Atomically set the proper flag */
325 slot->pss_signalFlags[reason] = true;
327 /* Send signal */
328 return kill(pid, SIGUSR1);
329 }
331 }
332 }
333 }
334
335 errno = ESRCH;
336 return -1;
337}

References Assert, fb(), i, INVALID_PROC_NUMBER, kill, NumProcSignalSlots, pg_atomic_read_u32(), ProcSignal, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_mutex, ProcSignalSlot::pss_pid, ProcSignalSlot::pss_signalFlags, SIGUSR1, SpinLockAcquire, and SpinLockRelease.

Referenced by CancelDBBackends(), InvalidatePossiblyObsoleteSlot(), mq_putmessage(), pa_shutdown(), ParallelWorkerShutdown(), pg_log_backend_memory_contexts(), SICleanupQueue(), SignalBackends(), SignalVirtualTransaction(), and WalSndInitStopping().

◆ WaitForProcSignalBarrier()

void WaitForProcSignalBarrier ( uint64  generation)

Definition at line 424 of file procsignal.c.

425{
427
428 elog(DEBUG1,
429 "waiting for all backends to process ProcSignalBarrier generation "
431 generation);
432
433 for (int i = NumProcSignalSlots - 1; i >= 0; i--)
434 {
437
438 /*
439 * It's important that we check only pss_barrierGeneration here and
440 * not pss_barrierCheckMask. Bits in pss_barrierCheckMask get cleared
441 * before the barrier is actually absorbed, but pss_barrierGeneration
442 * is updated only afterward.
443 */
445 while (oldval < generation)
446 {
448 5000,
450 ereport(LOG,
451 (errmsg("still waiting for backend with PID %d to accept ProcSignalBarrier",
452 (int) pg_atomic_read_u32(&slot->pss_pid))));
454 }
456 }
457
458 elog(DEBUG1,
459 "finished waiting for all backends to process ProcSignalBarrier generation "
461 generation);
462
463 /*
464 * The caller is probably calling this function because it wants to read
465 * the shared state or perform further writes to shared state once all
466 * backends are known to have absorbed the barrier. However, the read of
467 * pss_barrierGeneration was performed unlocked; insert a memory barrier
468 * to separate it from whatever follows.
469 */
471}

References Assert, ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), DEBUG1, elog, ereport, errmsg(), fb(), i, LOG, NumProcSignalSlots, pg_atomic_read_u32(), pg_atomic_read_u64(), pg_memory_barrier, ProcSignal, ProcSignalHeader::psh_barrierGeneration, ProcSignalHeader::psh_slot, ProcSignalSlot::pss_barrierCV, ProcSignalSlot::pss_barrierGeneration, ProcSignalSlot::pss_pid, and UINT64_FORMAT.

Referenced by dbase_redo(), dropdb(), DropTableSpace(), EnableLogicalDecoding(), movedb(), tblspc_redo(), and UpdateLogicalDecodingStatusEndOfRecovery().

Variable Documentation

◆ MyProcSignalSlot

◆ ProcSignal