Line data Source code
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" 35 : #include "postmaster/autovacuum.h" 36 : #include "postmaster/postmaster.h" 37 : #include "replication/walsender.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 : */ 46 : typedef 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 */ 52 : } PMChildPool; 53 : 54 : static PMChildPool pmchild_pools[BACKEND_NUM_TYPES]; 55 : NON_EXEC_STATIC int num_pmchild_slots = 0; 56 : 57 : /* 58 : * List of active child processes. This includes dead-end children. 59 : */ 60 : dlist_head ActiveChildList; 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 : */ 69 : int 70 9890 : MaxLivePostmasterChildren(void) 71 : { 72 9890 : if (num_pmchild_slots == 0) 73 0 : elog(ERROR, "PM child array not initialized yet"); 74 9890 : 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 : */ 85 : void 86 2028 : InitPostmasterChildSlots(void) 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 : */ 100 2028 : pmchild_pools[B_BACKEND].size = 2 * (MaxConnections + max_wal_senders); 101 : 102 2028 : pmchild_pools[B_AUTOVAC_WORKER].size = autovacuum_worker_slots; 103 2028 : pmchild_pools[B_BG_WORKER].size = max_worker_processes; 104 2028 : pmchild_pools[B_IO_WORKER].size = MAX_IO_WORKERS; 105 : 106 : /* 107 : * There can be only one of each of these running at a time. They each 108 : * get their own pool of just one entry. 109 : */ 110 2028 : pmchild_pools[B_AUTOVAC_LAUNCHER].size = 1; 111 2028 : pmchild_pools[B_SLOTSYNC_WORKER].size = 1; 112 2028 : pmchild_pools[B_ARCHIVER].size = 1; 113 2028 : pmchild_pools[B_BG_WRITER].size = 1; 114 2028 : pmchild_pools[B_CHECKPOINTER].size = 1; 115 2028 : pmchild_pools[B_STARTUP].size = 1; 116 2028 : pmchild_pools[B_WAL_RECEIVER].size = 1; 117 2028 : pmchild_pools[B_WAL_SUMMARIZER].size = 1; 118 2028 : pmchild_pools[B_WAL_WRITER].size = 1; 119 2028 : pmchild_pools[B_LOGGER].size = 1; 120 : 121 : /* The rest of the pmchild_pools are left at zero size */ 122 : 123 : /* Count the total number of slots */ 124 2028 : num_pmchild_slots = 0; 125 38532 : for (int i = 0; i < BACKEND_NUM_TYPES; i++) 126 36504 : num_pmchild_slots += pmchild_pools[i].size; 127 : 128 : /* Initialize them */ 129 2028 : slots = palloc(num_pmchild_slots * sizeof(PMChild)); 130 2028 : slotno = 0; 131 38532 : for (int btype = 0; btype < BACKEND_NUM_TYPES; btype++) 132 : { 133 36504 : pmchild_pools[btype].first_slotno = slotno + 1; 134 36504 : dlist_init(&pmchild_pools[btype].freelist); 135 : 136 453412 : for (int j = 0; j < pmchild_pools[btype].size; j++) 137 : { 138 416908 : slots[slotno].pid = 0; 139 416908 : slots[slotno].child_slot = slotno + 1; 140 416908 : slots[slotno].bkend_type = B_INVALID; 141 416908 : slots[slotno].rw = NULL; 142 416908 : slots[slotno].bgworker_notify = false; 143 416908 : dlist_push_tail(&pmchild_pools[btype].freelist, &slots[slotno].elem); 144 416908 : slotno++; 145 : } 146 : } 147 : Assert(slotno == num_pmchild_slots); 148 : 149 : /* Initialize other structures */ 150 2028 : dlist_init(&ActiveChildList); 151 2028 : } 152 : 153 : /* 154 : * Allocate a PMChild entry for a postmaster child process of given type. 155 : * 156 : * The entry is taken from the right pool for the type. 157 : * 158 : * pmchild->child_slot in the returned struct is unique among all active child 159 : * processes. 160 : */ 161 : PMChild * 162 47852 : AssignPostmasterChildSlot(BackendType btype) 163 : { 164 : dlist_head *freelist; 165 : PMChild *pmchild; 166 : 167 47852 : if (pmchild_pools[btype].size == 0) 168 0 : elog(ERROR, "cannot allocate a PMChild slot for backend type %d", btype); 169 : 170 47852 : freelist = &pmchild_pools[btype].freelist; 171 47852 : if (dlist_is_empty(freelist)) 172 56 : return NULL; 173 : 174 47796 : pmchild = dlist_container(PMChild, elem, dlist_pop_head_node(freelist)); 175 47796 : pmchild->pid = 0; 176 47796 : pmchild->bkend_type = btype; 177 47796 : pmchild->rw = NULL; 178 47796 : pmchild->bgworker_notify = true; 179 : 180 : /* 181 : * pmchild->child_slot for each entry was initialized when the array of 182 : * slots was allocated. Sanity check it. 183 : */ 184 47796 : if (!(pmchild->child_slot >= pmchild_pools[btype].first_slotno && 185 47796 : pmchild->child_slot < pmchild_pools[btype].first_slotno + pmchild_pools[btype].size)) 186 : { 187 0 : elog(ERROR, "pmchild freelist for backend type %d is corrupt", 188 : pmchild->bkend_type); 189 : } 190 : 191 47796 : dlist_push_head(&ActiveChildList, &pmchild->elem); 192 : 193 : /* Update the status in the shared memory array */ 194 47796 : MarkPostmasterChildSlotAssigned(pmchild->child_slot); 195 : 196 47796 : elog(DEBUG2, "assigned pm child slot %d for %s", 197 : pmchild->child_slot, PostmasterChildName(btype)); 198 : 199 47796 : return pmchild; 200 : } 201 : 202 : /* 203 : * Allocate a PMChild struct for a dead-end backend. Dead-end children are 204 : * not assigned a child_slot number. The struct is palloc'd; returns NULL if 205 : * out of memory. 206 : */ 207 : PMChild * 208 316 : AllocDeadEndChild(void) 209 : { 210 : PMChild *pmchild; 211 : 212 316 : elog(DEBUG2, "allocating dead-end child"); 213 : 214 316 : pmchild = (PMChild *) palloc_extended(sizeof(PMChild), MCXT_ALLOC_NO_OOM); 215 316 : if (pmchild) 216 : { 217 316 : pmchild->pid = 0; 218 316 : pmchild->child_slot = 0; 219 316 : pmchild->bkend_type = B_DEAD_END_BACKEND; 220 316 : pmchild->rw = NULL; 221 316 : pmchild->bgworker_notify = false; 222 : 223 316 : dlist_push_head(&ActiveChildList, &pmchild->elem); 224 : } 225 : 226 316 : return pmchild; 227 : } 228 : 229 : /* 230 : * Release a PMChild slot, after the child process has exited. 231 : * 232 : * Returns true if the child detached cleanly from shared memory, false 233 : * otherwise (see MarkPostmasterChildSlotUnassigned). 234 : */ 235 : bool 236 48048 : ReleasePostmasterChildSlot(PMChild *pmchild) 237 : { 238 48048 : dlist_delete(&pmchild->elem); 239 48048 : if (pmchild->bkend_type == B_DEAD_END_BACKEND) 240 : { 241 316 : elog(DEBUG2, "releasing dead-end backend"); 242 316 : pfree(pmchild); 243 316 : return true; 244 : } 245 : else 246 : { 247 : PMChildPool *pool; 248 : 249 47732 : elog(DEBUG2, "releasing pm child slot %d", pmchild->child_slot); 250 : 251 : /* WAL senders start out as regular backends, and share the pool */ 252 47732 : if (pmchild->bkend_type == B_WAL_SENDER) 253 68 : pool = &pmchild_pools[B_BACKEND]; 254 : else 255 47664 : pool = &pmchild_pools[pmchild->bkend_type]; 256 : 257 : /* sanity check that we return the entry to the right pool */ 258 47732 : if (!(pmchild->child_slot >= pool->first_slotno && 259 47732 : pmchild->child_slot < pool->first_slotno + pool->size)) 260 : { 261 0 : elog(ERROR, "pmchild freelist for backend type %d is corrupt", 262 : pmchild->bkend_type); 263 : } 264 : 265 47732 : dlist_push_head(&pool->freelist, &pmchild->elem); 266 47732 : return MarkPostmasterChildSlotUnassigned(pmchild->child_slot); 267 : } 268 : } 269 : 270 : /* 271 : * Find the PMChild entry of a running child process by PID. 272 : */ 273 : PMChild * 274 34886 : FindPostmasterChildByPid(int pid) 275 : { 276 : dlist_iter iter; 277 : 278 65314 : dlist_foreach(iter, &ActiveChildList) 279 : { 280 65314 : PMChild *bp = dlist_container(PMChild, elem, iter.cur); 281 : 282 65314 : if (bp->pid == pid) 283 34886 : return bp; 284 : } 285 0 : return NULL; 286 : }