PostgreSQL Source Code git master
pmchild.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pmchild.c
4 * Functions for keeping track of postmaster child processes.
5 *
6 * Postmaster keeps track of all child processes so that when a process exits,
7 * it knows what kind of a process it was and can clean up accordingly. Every
8 * child process is allocated a PMChild struct from a fixed pool of structs.
9 * The size of the pool is determined by various settings that configure how
10 * many worker processes and backend connections are allowed, i.e.
11 * autovacuum_worker_slots, max_worker_processes, max_wal_senders, and
12 * max_connections.
13 *
14 * Dead-end backends are handled slightly differently. There is no limit
15 * on the number of dead-end backends, and they do not need unique IDs, so
16 * their PMChild structs are allocated dynamically, not from a pool.
17 *
18 * The structures and functions in this file are private to the postmaster
19 * process. But note that there is an array in shared memory, managed by
20 * pmsignal.c, that mirrors this.
21 *
22 *
23 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
24 * Portions Copyright (c) 1994, Regents of the University of California
25 *
26 * IDENTIFICATION
27 * src/backend/postmaster/pmchild.c
28 *
29 *-------------------------------------------------------------------------
30 */
31
32#include "postgres.h"
33
34#include "miscadmin.h"
38#include "storage/pmsignal.h"
39#include "storage/proc.h"
40
41/*
42 * Freelists for different kinds of child processes. We maintain separate
43 * pools for each, so that for example launching a lot of regular backends
44 * cannot prevent autovacuum or an aux process from launching.
45 */
46typedef struct PMChildPool
47{
48 int size; /* number of PMChild slots reserved for this
49 * kind of processes */
50 int first_slotno; /* first slot belonging to this pool */
51 dlist_head freelist; /* currently unused PMChild entries */
53
56
57/*
58 * List of active child processes. This includes dead-end children.
59 */
61
62/*
63 * MaxLivePostmasterChildren
64 *
65 * This reports the number of postmaster child processes that can be active.
66 * It includes all children except for dead-end children. This allows the
67 * array in shared memory (PMChildFlags) to have a fixed maximum size.
68 */
69int
71{
72 if (num_pmchild_slots == 0)
73 elog(ERROR, "PM child array not initialized yet");
74 return num_pmchild_slots;
75}
76
77/*
78 * Initialize at postmaster startup
79 *
80 * Note: This is not called on crash restart. We rely on PMChild entries to
81 * remain valid through the restart process. This is important because the
82 * syslogger survives through the crash restart process, so we must not
83 * invalidate its PMChild slot.
84 */
85void
87{
88 int slotno;
89 PMChild *slots;
90
91 /*
92 * We allow more connections here than we can have backends because some
93 * might still be authenticating; they might fail auth, or some existing
94 * backend might exit before the auth cycle is completed. The exact
95 * MaxConnections limit is enforced when a new backend tries to join the
96 * PGPROC array.
97 *
98 * WAL senders start out as regular backends, so they share the same pool.
99 */
101
104
105 /*
106 * There can be only one of each of these running at a time. They each
107 * get their own pool of just one entry.
108 */
119
120 /* The rest of the pmchild_pools are left at zero size */
121
122 /* Count the total number of slots */
124 for (int i = 0; i < BACKEND_NUM_TYPES; i++)
126
127 /* Initialize them */
128 slots = palloc(num_pmchild_slots * sizeof(PMChild));
129 slotno = 0;
130 for (int btype = 0; btype < BACKEND_NUM_TYPES; btype++)
131 {
132 pmchild_pools[btype].first_slotno = slotno + 1;
133 dlist_init(&pmchild_pools[btype].freelist);
134
135 for (int j = 0; j < pmchild_pools[btype].size; j++)
136 {
137 slots[slotno].pid = 0;
138 slots[slotno].child_slot = slotno + 1;
139 slots[slotno].bkend_type = B_INVALID;
140 slots[slotno].rw = NULL;
141 slots[slotno].bgworker_notify = false;
142 dlist_push_tail(&pmchild_pools[btype].freelist, &slots[slotno].elem);
143 slotno++;
144 }
145 }
146 Assert(slotno == num_pmchild_slots);
147
148 /* Initialize other structures */
150}
151
152/*
153 * Allocate a PMChild entry for a postmaster child process of given type.
154 *
155 * The entry is taken from the right pool for the type.
156 *
157 * pmchild->child_slot in the returned struct is unique among all active child
158 * processes.
159 */
160PMChild *
162{
163 dlist_head *freelist;
164 PMChild *pmchild;
165
166 if (pmchild_pools[btype].size == 0)
167 elog(ERROR, "cannot allocate a PMChild slot for backend type %d", btype);
168
169 freelist = &pmchild_pools[btype].freelist;
170 if (dlist_is_empty(freelist))
171 return NULL;
172
173 pmchild = dlist_container(PMChild, elem, dlist_pop_head_node(freelist));
174 pmchild->pid = 0;
175 pmchild->bkend_type = btype;
176 pmchild->rw = NULL;
177 pmchild->bgworker_notify = true;
178
179 /*
180 * pmchild->child_slot for each entry was initialized when the array of
181 * slots was allocated. Sanity check it.
182 */
183 if (!(pmchild->child_slot >= pmchild_pools[btype].first_slotno &&
184 pmchild->child_slot < pmchild_pools[btype].first_slotno + pmchild_pools[btype].size))
185 {
186 elog(ERROR, "pmchild freelist for backend type %d is corrupt",
187 pmchild->bkend_type);
188 }
189
191
192 /* Update the status in the shared memory array */
194
195 elog(DEBUG2, "assigned pm child slot %d for %s",
196 pmchild->child_slot, PostmasterChildName(btype));
197
198 return pmchild;
199}
200
201/*
202 * Allocate a PMChild struct for a dead-end backend. Dead-end children are
203 * not assigned a child_slot number. The struct is palloc'd; returns NULL if
204 * out of memory.
205 */
206PMChild *
208{
209 PMChild *pmchild;
210
211 elog(DEBUG2, "allocating dead-end child");
212
213 pmchild = (PMChild *) palloc_extended(sizeof(PMChild), MCXT_ALLOC_NO_OOM);
214 if (pmchild)
215 {
216 pmchild->pid = 0;
217 pmchild->child_slot = 0;
219 pmchild->rw = NULL;
220 pmchild->bgworker_notify = false;
221
223 }
224
225 return pmchild;
226}
227
228/*
229 * Release a PMChild slot, after the child process has exited.
230 *
231 * Returns true if the child detached cleanly from shared memory, false
232 * otherwise (see MarkPostmasterChildSlotUnassigned).
233 */
234bool
236{
237 dlist_delete(&pmchild->elem);
238 if (pmchild->bkend_type == B_DEAD_END_BACKEND)
239 {
240 elog(DEBUG2, "releasing dead-end backend");
241 pfree(pmchild);
242 return true;
243 }
244 else
245 {
246 PMChildPool *pool;
247
248 elog(DEBUG2, "releasing pm child slot %d", pmchild->child_slot);
249
250 /* WAL senders start out as regular backends, and share the pool */
251 if (pmchild->bkend_type == B_WAL_SENDER)
252 pool = &pmchild_pools[B_BACKEND];
253 else
254 pool = &pmchild_pools[pmchild->bkend_type];
255
256 /* sanity check that we return the entry to the right pool */
257 if (!(pmchild->child_slot >= pool->first_slotno &&
258 pmchild->child_slot < pool->first_slotno + pool->size))
259 {
260 elog(ERROR, "pmchild freelist for backend type %d is corrupt",
261 pmchild->bkend_type);
262 }
263
264 dlist_push_head(&pool->freelist, &pmchild->elem);
266 }
267}
268
269/*
270 * Find the PMChild entry of a running child process by PID.
271 */
272PMChild *
274{
275 dlist_iter iter;
276
278 {
279 PMChild *bp = dlist_container(PMChild, elem, iter.cur);
280
281 if (bp->pid == pid)
282 return bp;
283 }
284 return NULL;
285}
int autovacuum_worker_slots
Definition: autovacuum.c:118
#define Assert(condition)
Definition: c.h:815
#define DEBUG2
Definition: elog.h:29
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define MCXT_ALLOC_NO_OOM
Definition: fe_memutils.h:29
int MaxConnections
Definition: globals.c:142
int max_worker_processes
Definition: globals.c:143
static dlist_node * dlist_pop_head_node(dlist_head *head)
Definition: ilist.h:450
#define dlist_foreach(iter, lhead)
Definition: ilist.h:623
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
static void dlist_delete(dlist_node *node)
Definition: ilist.h:405
static void dlist_push_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:347
static bool dlist_is_empty(const dlist_head *head)
Definition: ilist.h:336
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
#define dlist_container(type, membername, ptr)
Definition: ilist.h:593
int j
Definition: isn.c:73
int i
Definition: isn.c:72
const char * PostmasterChildName(BackendType child_type)
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
void * palloc_extended(Size size, int flags)
Definition: mcxt.c:1368
#define BACKEND_NUM_TYPES
Definition: miscadmin.h:375
BackendType
Definition: miscadmin.h:337
@ B_WAL_SUMMARIZER
Definition: miscadmin.h:365
@ B_WAL_WRITER
Definition: miscadmin.h:366
@ B_WAL_RECEIVER
Definition: miscadmin.h:364
@ B_CHECKPOINTER
Definition: miscadmin.h:362
@ B_WAL_SENDER
Definition: miscadmin.h:346
@ B_LOGGER
Definition: miscadmin.h:372
@ B_STARTUP
Definition: miscadmin.h:363
@ B_BG_WORKER
Definition: miscadmin.h:345
@ B_INVALID
Definition: miscadmin.h:338
@ B_BG_WRITER
Definition: miscadmin.h:361
@ B_BACKEND
Definition: miscadmin.h:341
@ B_ARCHIVER
Definition: miscadmin.h:360
@ B_AUTOVAC_LAUNCHER
Definition: miscadmin.h:343
@ B_SLOTSYNC_WORKER
Definition: miscadmin.h:347
@ B_DEAD_END_BACKEND
Definition: miscadmin.h:342
@ B_AUTOVAC_WORKER
Definition: miscadmin.h:344
NON_EXEC_STATIC int num_pmchild_slots
Definition: pmchild.c:55
PMChild * AssignPostmasterChildSlot(BackendType btype)
Definition: pmchild.c:161
bool ReleasePostmasterChildSlot(PMChild *pmchild)
Definition: pmchild.c:235
static PMChildPool pmchild_pools[BACKEND_NUM_TYPES]
Definition: pmchild.c:54
void InitPostmasterChildSlots(void)
Definition: pmchild.c:86
PMChild * AllocDeadEndChild(void)
Definition: pmchild.c:207
int MaxLivePostmasterChildren(void)
Definition: pmchild.c:70
dlist_head ActiveChildList
Definition: pmchild.c:60
PMChild * FindPostmasterChildByPid(int pid)
Definition: pmchild.c:273
struct PMChildPool PMChildPool
void MarkPostmasterChildSlotAssigned(int slot)
Definition: pmsignal.c:230
bool MarkPostmasterChildSlotUnassigned(int slot)
Definition: pmsignal.c:249
#define NON_EXEC_STATIC
Definition: postgres.h:581
static pg_noinline void Size size
Definition: slab.c:607
int first_slotno
Definition: pmchild.c:50
int size
Definition: pmchild.c:48
dlist_head freelist
Definition: pmchild.c:51
struct RegisteredBgWorker * rw
Definition: postmaster.h:45
bool bgworker_notify
Definition: postmaster.h:46
BackendType bkend_type
Definition: postmaster.h:44
dlist_node elem
Definition: postmaster.h:47
pid_t pid
Definition: postmaster.h:42
int child_slot
Definition: postmaster.h:43
dlist_node * cur
Definition: ilist.h:179
int max_wal_senders
Definition: walsender.c:121