From 66e05e49737446340615a7968c7d4074951227d5 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 13 Feb 2026 14:23:35 +0200 Subject: [PATCH v12 1/4] Refactor how some aux processes advertise their ProcNumber This moves the responsibility of setting the ProcGlobal->walrewriterProc and checkpointerProc fields to InitAuxiliaryProcess. Also switch to the same pattern to advertise the autovacuum launcher's ProcNumber, replacing the ad hoc av_launcherpid field in shared memory. This can easily be extended to other aux processes in the future, if other processes need to find them. Switch to pg_atomic_uint32 for the fields. Seems easier to reason about than volatile pointers. There was some precedence for that, as were already using pg_atomic_uint32 for the procArrayGroupFirst and clogGroupFirst fields, which also store ProcNumbers. TODO: could also replace WalRecv->procno with this --- src/backend/access/transam/xlog.c | 3 +-- src/backend/postmaster/autovacuum.c | 19 +++++++++-------- src/backend/postmaster/checkpointer.c | 14 ++++--------- src/backend/postmaster/walwriter.c | 6 ------ src/backend/storage/lmgr/proc.c | 30 +++++++++++++++++++++++++-- src/include/storage/proc.h | 7 ++++--- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 354ac645bdc..129bb224d7d 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2636,8 +2636,7 @@ XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN) if (wakeup) { - volatile PROC_HDR *procglobal = ProcGlobal; - ProcNumber walwriterProc = procglobal->walwriterProc; + ProcNumber walwriterProc = pg_atomic_read_u32(&ProcGlobal->walwriterProc); if (walwriterProc != INVALID_PROC_NUMBER) SetLatch(&GetPGProcByNumber(walwriterProc)->procLatch); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 6fde740465f..5d4eea4a1e3 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -277,7 +277,6 @@ typedef struct AutoVacuumWorkItem * struct and the array of WorkerInfo structs. This struct keeps: * * av_signal set by other processes to indicate various conditions - * av_launcherpid the PID of the autovacuum launcher * av_freeWorkers the WorkerInfo freelist * av_runningWorkers the WorkerInfo non-free queue * av_startingWorker pointer to WorkerInfo currently being started (cleared by @@ -293,7 +292,6 @@ typedef struct AutoVacuumWorkItem typedef struct { sig_atomic_t av_signal[AutoVacNumSignals]; - pid_t av_launcherpid; dclist_head av_freeWorkers; dlist_head av_runningWorkers; WorkerInfo av_startingWorker; @@ -564,8 +562,6 @@ AutoVacLauncherMain(const void *startup_data, size_t startup_data_len) proc_exit(0); /* done */ } - AutoVacuumShmem->av_launcherpid = MyProcPid; - /* * Create the initial database list. The invariant we want this list to * keep is that it's ordered by decreasing next_worker. As soon as an @@ -799,8 +795,6 @@ AutoVacLauncherShutdown(void) { ereport(DEBUG1, (errmsg_internal("autovacuum launcher shutting down"))); - AutoVacuumShmem->av_launcherpid = 0; - proc_exit(0); /* done */ } @@ -1531,6 +1525,8 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len) */ if (AutoVacuumShmem->av_startingWorker != NULL) { + ProcNumber launcherProc; + MyWorkerInfo = AutoVacuumShmem->av_startingWorker; dbid = MyWorkerInfo->wi_dboid; MyWorkerInfo->wi_proc = MyProc; @@ -1549,8 +1545,14 @@ AutoVacWorkerMain(const void *startup_data, size_t startup_data_len) on_shmem_exit(FreeWorkerInfo, 0); /* wake up the launcher */ - if (AutoVacuumShmem->av_launcherpid != 0) - kill(AutoVacuumShmem->av_launcherpid, SIGUSR2); + launcherProc = pg_atomic_read_u32(&ProcGlobal->avLauncherProc); + if (launcherProc != INVALID_PROC_NUMBER) + { + int pid = GetPGProcByNumber(launcherProc)->pid; + + if (pid != 0) + kill(pid, SIGUSR2); + } } else { @@ -3393,7 +3395,6 @@ AutoVacuumShmemInit(void) Assert(!found); - AutoVacuumShmem->av_launcherpid = 0; dclist_init(&AutoVacuumShmem->av_freeWorkers); dlist_init(&AutoVacuumShmem->av_runningWorkers); AutoVacuumShmem->av_startingWorker = NULL; diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index e03c19123bc..f1439d9a363 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -47,6 +47,7 @@ #include "libpq/pqsignal.h" #include "miscadmin.h" #include "pgstat.h" +#include "port/atomics.h" #include "postmaster/auxprocess.h" #include "postmaster/bgwriter.h" #include "postmaster/interrupt.h" @@ -348,12 +349,6 @@ CheckpointerMain(const void *startup_data, size_t startup_data_len) */ UpdateSharedMemoryConfig(); - /* - * Advertise our proc number that backends can use to wake us up while - * we're sleeping. - */ - ProcGlobal->checkpointerProc = MyProcNumber; - /* * Loop until we've been asked to write the shutdown checkpoint or * terminate. @@ -1125,7 +1120,7 @@ RequestCheckpoint(int flags) for (ntries = 0;; ntries++) { volatile PROC_HDR *procglobal = ProcGlobal; - ProcNumber checkpointerProc = procglobal->checkpointerProc; + ProcNumber checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc); if (checkpointerProc == INVALID_PROC_NUMBER) { @@ -1266,8 +1261,7 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type) /* ... but not till after we release the lock */ if (too_full) { - volatile PROC_HDR *procglobal = ProcGlobal; - ProcNumber checkpointerProc = procglobal->checkpointerProc; + ProcNumber checkpointerProc = pg_atomic_read_u32(&ProcGlobal->checkpointerProc); if (checkpointerProc != INVALID_PROC_NUMBER) SetLatch(&GetPGProcByNumber(checkpointerProc)->procLatch); @@ -1548,7 +1542,7 @@ void WakeupCheckpointer(void) { volatile PROC_HDR *procglobal = ProcGlobal; - ProcNumber checkpointerProc = procglobal->checkpointerProc; + ProcNumber checkpointerProc = pg_atomic_read_u32(&procglobal->checkpointerProc); if (checkpointerProc != INVALID_PROC_NUMBER) SetLatch(&GetPGProcByNumber(checkpointerProc)->procLatch); diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 7c0e2809c17..a0ed1e61420 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -205,12 +205,6 @@ WalWriterMain(const void *startup_data, size_t startup_data_len) hibernating = false; SetWalWriterSleeping(false); - /* - * Advertise our proc number that backends can use to wake us up while - * we're sleeping. - */ - ProcGlobal->walwriterProc = MyProcNumber; - /* * Loop forever */ diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index ccf9de0e67c..e001cb11803 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -211,8 +211,9 @@ InitProcGlobal(void) dlist_init(&ProcGlobal->bgworkerFreeProcs); dlist_init(&ProcGlobal->walsenderFreeProcs); ProcGlobal->startupBufferPinWaitBufId = -1; - ProcGlobal->walwriterProc = INVALID_PROC_NUMBER; - ProcGlobal->checkpointerProc = INVALID_PROC_NUMBER; + pg_atomic_init_u32(&ProcGlobal->avLauncherProc, INVALID_PROC_NUMBER); + pg_atomic_init_u32(&ProcGlobal->walwriterProc, INVALID_PROC_NUMBER); + pg_atomic_init_u32(&ProcGlobal->checkpointerProc, INVALID_PROC_NUMBER); pg_atomic_init_u32(&ProcGlobal->procArrayGroupFirst, INVALID_PROC_NUMBER); pg_atomic_init_u32(&ProcGlobal->clogGroupFirst, INVALID_PROC_NUMBER); @@ -711,6 +712,14 @@ InitAuxiliaryProcess(void) */ PGSemaphoreReset(MyProc->sem); + /* Some aux processes are also advertised in ProcGlobal */ + if (MyBackendType == B_AUTOVAC_LAUNCHER) + pg_atomic_write_u32(&ProcGlobal->avLauncherProc, MyProcNumber); + if (MyBackendType == B_WAL_WRITER) + pg_atomic_write_u32(&ProcGlobal->walwriterProc, MyProcNumber); + if (MyBackendType == B_CHECKPOINTER) + pg_atomic_write_u32(&ProcGlobal->checkpointerProc, MyProcNumber); + /* * Arrange to clean up at process exit. */ @@ -1055,6 +1064,23 @@ AuxiliaryProcKill(int code, Datum arg) SwitchBackToLocalLatch(); pgstat_reset_wait_event_storage(); + /* If this was one of aux processes advertised in ProcGlobal, clear it */ + if (MyBackendType == B_AUTOVAC_LAUNCHER) + { + Assert(pg_atomic_read_u32(&ProcGlobal->avLauncherProc) == MyProcNumber); + pg_atomic_write_u32(&ProcGlobal->avLauncherProc, INVALID_PROC_NUMBER); + } + if (MyBackendType == B_WAL_WRITER) + { + Assert(pg_atomic_read_u32(&ProcGlobal->walwriterProc) == MyProcNumber); + pg_atomic_write_u32(&ProcGlobal->walwriterProc, INVALID_PROC_NUMBER); + } + if (MyBackendType == B_CHECKPOINTER) + { + Assert(pg_atomic_read_u32(&ProcGlobal->checkpointerProc) == MyProcNumber); + pg_atomic_write_u32(&ProcGlobal->checkpointerProc, INVALID_PROC_NUMBER); + } + proc = MyProc; MyProc = NULL; MyProcNumber = INVALID_PROC_NUMBER; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 3f89450c216..4a1fafb9038 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -488,11 +488,12 @@ typedef struct PROC_HDR pg_atomic_uint32 clogGroupFirst; /* - * Current slot numbers of some auxiliary processes. There can be only one + * Current proc numbers of some auxiliary processes. There can be only one * of each of these running at a time. */ - ProcNumber walwriterProc; - ProcNumber checkpointerProc; + pg_atomic_uint32 avLauncherProc; + pg_atomic_uint32 walwriterProc; + pg_atomic_uint32 checkpointerProc; /* Current shared estimate of appropriate spins_per_delay value */ int spins_per_delay; -- 2.47.3