Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/storage/ipc/ipci.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * ipci.c
4
 *    POSTGRES inter-process communication initialization code.
5
 *
6
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/storage/ipc/ipci.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
#include "postgres.h"
16
17
#include "access/clog.h"
18
#include "access/commit_ts.h"
19
#include "access/multixact.h"
20
#include "access/nbtree.h"
21
#include "access/subtrans.h"
22
#include "access/syncscan.h"
23
#include "access/transam.h"
24
#include "access/twophase.h"
25
#include "access/xlogprefetcher.h"
26
#include "access/xlogrecovery.h"
27
#include "commands/async.h"
28
#include "miscadmin.h"
29
#include "pgstat.h"
30
#include "postmaster/autovacuum.h"
31
#include "postmaster/bgworker_internals.h"
32
#include "postmaster/bgwriter.h"
33
#include "postmaster/walsummarizer.h"
34
#include "replication/logicallauncher.h"
35
#include "replication/origin.h"
36
#include "replication/slot.h"
37
#include "replication/slotsync.h"
38
#include "replication/walreceiver.h"
39
#include "replication/walsender.h"
40
#include "storage/aio_subsys.h"
41
#include "storage/bufmgr.h"
42
#include "storage/dsm.h"
43
#include "storage/dsm_registry.h"
44
#include "storage/ipc.h"
45
#include "storage/pg_shmem.h"
46
#include "storage/pmsignal.h"
47
#include "storage/predicate.h"
48
#include "storage/proc.h"
49
#include "storage/procarray.h"
50
#include "storage/procsignal.h"
51
#include "storage/sinvaladt.h"
52
#include "utils/guc.h"
53
#include "utils/injection_point.h"
54
55
/* GUCs */
56
int     shared_memory_type = DEFAULT_SHARED_MEMORY_TYPE;
57
58
shmem_startup_hook_type shmem_startup_hook = NULL;
59
60
static Size total_addin_request = 0;
61
62
static void CreateOrAttachShmemStructs(void);
63
64
/*
65
 * RequestAddinShmemSpace
66
 *    Request that extra shmem space be allocated for use by
67
 *    a loadable module.
68
 *
69
 * This may only be called via the shmem_request_hook of a library that is
70
 * loaded into the postmaster via shared_preload_libraries.  Calls from
71
 * elsewhere will fail.
72
 */
73
void
74
RequestAddinShmemSpace(Size size)
75
0
{
76
0
  if (!process_shmem_requests_in_progress)
77
0
    elog(FATAL, "cannot request additional shared memory outside shmem_request_hook");
78
0
  total_addin_request = add_size(total_addin_request, size);
79
0
}
80
81
/*
82
 * CalculateShmemSize
83
 *    Calculates the amount of shared memory and number of semaphores needed.
84
 *
85
 * If num_semaphores is not NULL, it will be set to the number of semaphores
86
 * required.
87
 */
88
Size
89
CalculateShmemSize(int *num_semaphores)
90
0
{
91
0
  Size    size;
92
0
  int     numSemas;
93
94
  /* Compute number of semaphores we'll need */
95
0
  numSemas = ProcGlobalSemas();
96
97
  /* Return the number of semaphores if requested by the caller */
98
0
  if (num_semaphores)
99
0
    *num_semaphores = numSemas;
100
101
  /*
102
   * Size of the Postgres shared-memory block is estimated via moderately-
103
   * accurate estimates for the big hogs, plus 100K for the stuff that's too
104
   * small to bother with estimating.
105
   *
106
   * We take some care to ensure that the total size request doesn't
107
   * overflow size_t.  If this gets through, we don't need to be so careful
108
   * during the actual allocation phase.
109
   */
110
0
  size = 100000;
111
0
  size = add_size(size, PGSemaphoreShmemSize(numSemas));
112
0
  size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
113
0
                       sizeof(ShmemIndexEnt)));
114
0
  size = add_size(size, dsm_estimate_size());
115
0
  size = add_size(size, DSMRegistryShmemSize());
116
0
  size = add_size(size, BufferManagerShmemSize());
117
0
  size = add_size(size, LockManagerShmemSize());
118
0
  size = add_size(size, PredicateLockShmemSize());
119
0
  size = add_size(size, ProcGlobalShmemSize());
120
0
  size = add_size(size, XLogPrefetchShmemSize());
121
0
  size = add_size(size, VarsupShmemSize());
122
0
  size = add_size(size, XLOGShmemSize());
123
0
  size = add_size(size, XLogRecoveryShmemSize());
124
0
  size = add_size(size, CLOGShmemSize());
125
0
  size = add_size(size, CommitTsShmemSize());
126
0
  size = add_size(size, SUBTRANSShmemSize());
127
0
  size = add_size(size, TwoPhaseShmemSize());
128
0
  size = add_size(size, BackgroundWorkerShmemSize());
129
0
  size = add_size(size, MultiXactShmemSize());
130
0
  size = add_size(size, LWLockShmemSize());
131
0
  size = add_size(size, ProcArrayShmemSize());
132
0
  size = add_size(size, BackendStatusShmemSize());
133
0
  size = add_size(size, SharedInvalShmemSize());
134
0
  size = add_size(size, PMSignalShmemSize());
135
0
  size = add_size(size, ProcSignalShmemSize());
136
0
  size = add_size(size, CheckpointerShmemSize());
137
0
  size = add_size(size, AutoVacuumShmemSize());
138
0
  size = add_size(size, ReplicationSlotsShmemSize());
139
0
  size = add_size(size, ReplicationOriginShmemSize());
140
0
  size = add_size(size, WalSndShmemSize());
141
0
  size = add_size(size, WalRcvShmemSize());
142
0
  size = add_size(size, WalSummarizerShmemSize());
143
0
  size = add_size(size, PgArchShmemSize());
144
0
  size = add_size(size, ApplyLauncherShmemSize());
145
0
  size = add_size(size, BTreeShmemSize());
146
0
  size = add_size(size, SyncScanShmemSize());
147
0
  size = add_size(size, AsyncShmemSize());
148
0
  size = add_size(size, StatsShmemSize());
149
0
  size = add_size(size, WaitEventCustomShmemSize());
150
0
  size = add_size(size, InjectionPointShmemSize());
151
0
  size = add_size(size, SlotSyncShmemSize());
152
0
  size = add_size(size, AioShmemSize());
153
154
  /* include additional requested shmem from preload libraries */
155
0
  size = add_size(size, total_addin_request);
156
157
  /* might as well round it off to a multiple of a typical page size */
158
0
  size = add_size(size, 8192 - (size % 8192));
159
160
0
  return size;
161
0
}
162
163
#ifdef EXEC_BACKEND
164
/*
165
 * AttachSharedMemoryStructs
166
 *    Initialize a postmaster child process's access to shared memory
167
 *      structures.
168
 *
169
 * In !EXEC_BACKEND mode, we inherit everything through the fork, and this
170
 * isn't needed.
171
 */
172
void
173
AttachSharedMemoryStructs(void)
174
{
175
  /* InitProcess must've been called already */
176
  Assert(MyProc != NULL);
177
  Assert(IsUnderPostmaster);
178
179
  /*
180
   * In EXEC_BACKEND mode, backends don't inherit the number of fast-path
181
   * groups we calculated before setting the shmem up, so recalculate it.
182
   */
183
  InitializeFastPathLocks();
184
185
  CreateOrAttachShmemStructs();
186
187
  /*
188
   * Now give loadable modules a chance to set up their shmem allocations
189
   */
190
  if (shmem_startup_hook)
191
    shmem_startup_hook();
192
}
193
#endif
194
195
/*
196
 * CreateSharedMemoryAndSemaphores
197
 *    Creates and initializes shared memory and semaphores.
198
 */
199
void
200
CreateSharedMemoryAndSemaphores(void)
201
0
{
202
0
  PGShmemHeader *shim;
203
0
  PGShmemHeader *seghdr;
204
0
  Size    size;
205
0
  int     numSemas;
206
207
0
  Assert(!IsUnderPostmaster);
208
209
  /* Compute the size of the shared-memory block */
210
0
  size = CalculateShmemSize(&numSemas);
211
0
  elog(DEBUG3, "invoking IpcMemoryCreate(size=%zu)", size);
212
213
  /*
214
   * Create the shmem segment
215
   */
216
0
  seghdr = PGSharedMemoryCreate(size, &shim);
217
218
  /*
219
   * Make sure that huge pages are never reported as "unknown" while the
220
   * server is running.
221
   */
222
0
  Assert(strcmp("unknown",
223
0
          GetConfigOption("huge_pages_status", false, false)) != 0);
224
225
0
  InitShmemAccess(seghdr);
226
227
  /*
228
   * Create semaphores
229
   */
230
0
  PGReserveSemaphores(numSemas);
231
232
  /*
233
   * Set up shared memory allocation mechanism
234
   */
235
0
  InitShmemAllocation();
236
237
  /* Initialize subsystems */
238
0
  CreateOrAttachShmemStructs();
239
240
  /* Initialize dynamic shared memory facilities. */
241
0
  dsm_postmaster_startup(shim);
242
243
  /*
244
   * Now give loadable modules a chance to set up their shmem allocations
245
   */
246
0
  if (shmem_startup_hook)
247
0
    shmem_startup_hook();
248
0
}
249
250
/*
251
 * Initialize various subsystems, setting up their data structures in
252
 * shared memory.
253
 *
254
 * This is called by the postmaster or by a standalone backend.
255
 * It is also called by a backend forked from the postmaster in the
256
 * EXEC_BACKEND case.  In the latter case, the shared memory segment
257
 * already exists and has been physically attached to, but we have to
258
 * initialize pointers in local memory that reference the shared structures,
259
 * because we didn't inherit the correct pointer values from the postmaster
260
 * as we do in the fork() scenario.  The easiest way to do that is to run
261
 * through the same code as before.  (Note that the called routines mostly
262
 * check IsUnderPostmaster, rather than EXEC_BACKEND, to detect this case.
263
 * This is a bit code-wasteful and could be cleaned up.)
264
 */
265
static void
266
CreateOrAttachShmemStructs(void)
267
0
{
268
  /*
269
   * Now initialize LWLocks, which do shared memory allocation and are
270
   * needed for InitShmemIndex.
271
   */
272
0
  CreateLWLocks();
273
274
  /*
275
   * Set up shmem.c index hashtable
276
   */
277
0
  InitShmemIndex();
278
279
0
  dsm_shmem_init();
280
0
  DSMRegistryShmemInit();
281
282
  /*
283
   * Set up xlog, clog, and buffers
284
   */
285
0
  VarsupShmemInit();
286
0
  XLOGShmemInit();
287
0
  XLogPrefetchShmemInit();
288
0
  XLogRecoveryShmemInit();
289
0
  CLOGShmemInit();
290
0
  CommitTsShmemInit();
291
0
  SUBTRANSShmemInit();
292
0
  MultiXactShmemInit();
293
0
  BufferManagerShmemInit();
294
295
  /*
296
   * Set up lock manager
297
   */
298
0
  LockManagerShmemInit();
299
300
  /*
301
   * Set up predicate lock manager
302
   */
303
0
  PredicateLockShmemInit();
304
305
  /*
306
   * Set up process table
307
   */
308
0
  if (!IsUnderPostmaster)
309
0
    InitProcGlobal();
310
0
  ProcArrayShmemInit();
311
0
  BackendStatusShmemInit();
312
0
  TwoPhaseShmemInit();
313
0
  BackgroundWorkerShmemInit();
314
315
  /*
316
   * Set up shared-inval messaging
317
   */
318
0
  SharedInvalShmemInit();
319
320
  /*
321
   * Set up interprocess signaling mechanisms
322
   */
323
0
  PMSignalShmemInit();
324
0
  ProcSignalShmemInit();
325
0
  CheckpointerShmemInit();
326
0
  AutoVacuumShmemInit();
327
0
  ReplicationSlotsShmemInit();
328
0
  ReplicationOriginShmemInit();
329
0
  WalSndShmemInit();
330
0
  WalRcvShmemInit();
331
0
  WalSummarizerShmemInit();
332
0
  PgArchShmemInit();
333
0
  ApplyLauncherShmemInit();
334
0
  SlotSyncShmemInit();
335
336
  /*
337
   * Set up other modules that need some shared memory space
338
   */
339
0
  BTreeShmemInit();
340
0
  SyncScanShmemInit();
341
0
  AsyncShmemInit();
342
0
  StatsShmemInit();
343
0
  WaitEventCustomShmemInit();
344
0
  InjectionPointShmemInit();
345
0
  AioShmemInit();
346
0
}
347
348
/*
349
 * InitializeShmemGUCs
350
 *
351
 * This function initializes runtime-computed GUCs related to the amount of
352
 * shared memory required for the current configuration.
353
 */
354
void
355
InitializeShmemGUCs(void)
356
0
{
357
0
  char    buf[64];
358
0
  Size    size_b;
359
0
  Size    size_mb;
360
0
  Size    hp_size;
361
0
  int     num_semas;
362
363
  /*
364
   * Calculate the shared memory size and round up to the nearest megabyte.
365
   */
366
0
  size_b = CalculateShmemSize(&num_semas);
367
0
  size_mb = add_size(size_b, (1024 * 1024) - 1) / (1024 * 1024);
368
0
  sprintf(buf, "%zu", size_mb);
369
0
  SetConfigOption("shared_memory_size", buf,
370
0
          PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
371
372
  /*
373
   * Calculate the number of huge pages required.
374
   */
375
0
  GetHugePageSize(&hp_size, NULL);
376
0
  if (hp_size != 0)
377
0
  {
378
0
    Size    hp_required;
379
380
0
    hp_required = add_size(size_b / hp_size, 1);
381
0
    sprintf(buf, "%zu", hp_required);
382
0
    SetConfigOption("shared_memory_size_in_huge_pages", buf,
383
0
            PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
384
0
  }
385
386
0
  sprintf(buf, "%d", num_semas);
387
0
  SetConfigOption("num_os_semaphores", buf, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
388
0
}