Line data Source code
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 26 : RequestAddinShmemSpace(Size size)
75 : {
76 26 : if (!process_shmem_requests_in_progress)
77 0 : elog(FATAL, "cannot request additional shared memory outside shmem_request_hook");
78 26 : total_addin_request = add_size(total_addin_request, size);
79 26 : }
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 3794 : CalculateShmemSize(int *num_semaphores)
90 : {
91 : Size size;
92 : int numSemas;
93 :
94 : /* Compute number of semaphores we'll need */
95 3794 : numSemas = ProcGlobalSemas();
96 :
97 : /* Return the number of semaphores if requested by the caller */
98 3794 : if (num_semaphores)
99 3794 : *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 3794 : size = 100000;
111 3794 : size = add_size(size, PGSemaphoreShmemSize(numSemas));
112 3794 : size = add_size(size, hash_estimate_size(SHMEM_INDEX_SIZE,
113 : sizeof(ShmemIndexEnt)));
114 3794 : size = add_size(size, dsm_estimate_size());
115 3794 : size = add_size(size, DSMRegistryShmemSize());
116 3794 : size = add_size(size, BufferManagerShmemSize());
117 3794 : size = add_size(size, LockManagerShmemSize());
118 3794 : size = add_size(size, PredicateLockShmemSize());
119 3794 : size = add_size(size, ProcGlobalShmemSize());
120 3794 : size = add_size(size, XLogPrefetchShmemSize());
121 3794 : size = add_size(size, VarsupShmemSize());
122 3794 : size = add_size(size, XLOGShmemSize());
123 3794 : size = add_size(size, XLogRecoveryShmemSize());
124 3794 : size = add_size(size, CLOGShmemSize());
125 3794 : size = add_size(size, CommitTsShmemSize());
126 3794 : size = add_size(size, SUBTRANSShmemSize());
127 3794 : size = add_size(size, TwoPhaseShmemSize());
128 3794 : size = add_size(size, BackgroundWorkerShmemSize());
129 3794 : size = add_size(size, MultiXactShmemSize());
130 3794 : size = add_size(size, LWLockShmemSize());
131 3794 : size = add_size(size, ProcArrayShmemSize());
132 3794 : size = add_size(size, BackendStatusShmemSize());
133 3794 : size = add_size(size, SharedInvalShmemSize());
134 3794 : size = add_size(size, PMSignalShmemSize());
135 3794 : size = add_size(size, ProcSignalShmemSize());
136 3794 : size = add_size(size, CheckpointerShmemSize());
137 3794 : size = add_size(size, AutoVacuumShmemSize());
138 3794 : size = add_size(size, ReplicationSlotsShmemSize());
139 3794 : size = add_size(size, ReplicationOriginShmemSize());
140 3794 : size = add_size(size, WalSndShmemSize());
141 3794 : size = add_size(size, WalRcvShmemSize());
142 3794 : size = add_size(size, WalSummarizerShmemSize());
143 3794 : size = add_size(size, PgArchShmemSize());
144 3794 : size = add_size(size, ApplyLauncherShmemSize());
145 3794 : size = add_size(size, BTreeShmemSize());
146 3794 : size = add_size(size, SyncScanShmemSize());
147 3794 : size = add_size(size, AsyncShmemSize());
148 3794 : size = add_size(size, StatsShmemSize());
149 3794 : size = add_size(size, WaitEventCustomShmemSize());
150 3794 : size = add_size(size, InjectionPointShmemSize());
151 3794 : size = add_size(size, SlotSyncShmemSize());
152 3794 : size = add_size(size, AioShmemSize());
153 :
154 : /* include additional requested shmem from preload libraries */
155 3794 : size = add_size(size, total_addin_request);
156 :
157 : /* might as well round it off to a multiple of a typical page size */
158 3794 : size = add_size(size, 8192 - (size % 8192));
159 :
160 3794 : return size;
161 : }
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 2036 : CreateSharedMemoryAndSemaphores(void)
201 : {
202 : PGShmemHeader *shim;
203 : PGShmemHeader *seghdr;
204 : Size size;
205 : int numSemas;
206 :
207 : Assert(!IsUnderPostmaster);
208 :
209 : /* Compute the size of the shared-memory block */
210 2036 : size = CalculateShmemSize(&numSemas);
211 2036 : elog(DEBUG3, "invoking IpcMemoryCreate(size=%zu)", size);
212 :
213 : /*
214 : * Create the shmem segment
215 : */
216 2036 : 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 : Assert(strcmp("unknown",
223 : GetConfigOption("huge_pages_status", false, false)) != 0);
224 :
225 2032 : InitShmemAccess(seghdr);
226 :
227 : /*
228 : * Create semaphores
229 : */
230 2032 : PGReserveSemaphores(numSemas);
231 :
232 : /*
233 : * Set up shared memory allocation mechanism
234 : */
235 2032 : InitShmemAllocation();
236 :
237 : /* Initialize subsystems */
238 2032 : CreateOrAttachShmemStructs();
239 :
240 : /* Initialize dynamic shared memory facilities. */
241 2032 : dsm_postmaster_startup(shim);
242 :
243 : /*
244 : * Now give loadable modules a chance to set up their shmem allocations
245 : */
246 2032 : if (shmem_startup_hook)
247 24 : shmem_startup_hook();
248 2032 : }
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 2032 : CreateOrAttachShmemStructs(void)
267 : {
268 : /*
269 : * Now initialize LWLocks, which do shared memory allocation and are
270 : * needed for InitShmemIndex.
271 : */
272 2032 : CreateLWLocks();
273 :
274 : /*
275 : * Set up shmem.c index hashtable
276 : */
277 2032 : InitShmemIndex();
278 :
279 2032 : dsm_shmem_init();
280 2032 : DSMRegistryShmemInit();
281 :
282 : /*
283 : * Set up xlog, clog, and buffers
284 : */
285 2032 : VarsupShmemInit();
286 2032 : XLOGShmemInit();
287 2032 : XLogPrefetchShmemInit();
288 2032 : XLogRecoveryShmemInit();
289 2032 : CLOGShmemInit();
290 2032 : CommitTsShmemInit();
291 2032 : SUBTRANSShmemInit();
292 2032 : MultiXactShmemInit();
293 2032 : BufferManagerShmemInit();
294 :
295 : /*
296 : * Set up lock manager
297 : */
298 2032 : LockManagerShmemInit();
299 :
300 : /*
301 : * Set up predicate lock manager
302 : */
303 2032 : PredicateLockShmemInit();
304 :
305 : /*
306 : * Set up process table
307 : */
308 2032 : if (!IsUnderPostmaster)
309 2032 : InitProcGlobal();
310 2032 : ProcArrayShmemInit();
311 2032 : BackendStatusShmemInit();
312 2032 : TwoPhaseShmemInit();
313 2032 : BackgroundWorkerShmemInit();
314 :
315 : /*
316 : * Set up shared-inval messaging
317 : */
318 2032 : SharedInvalShmemInit();
319 :
320 : /*
321 : * Set up interprocess signaling mechanisms
322 : */
323 2032 : PMSignalShmemInit();
324 2032 : ProcSignalShmemInit();
325 2032 : CheckpointerShmemInit();
326 2032 : AutoVacuumShmemInit();
327 2032 : ReplicationSlotsShmemInit();
328 2032 : ReplicationOriginShmemInit();
329 2032 : WalSndShmemInit();
330 2032 : WalRcvShmemInit();
331 2032 : WalSummarizerShmemInit();
332 2032 : PgArchShmemInit();
333 2032 : ApplyLauncherShmemInit();
334 2032 : SlotSyncShmemInit();
335 :
336 : /*
337 : * Set up other modules that need some shared memory space
338 : */
339 2032 : BTreeShmemInit();
340 2032 : SyncScanShmemInit();
341 2032 : AsyncShmemInit();
342 2032 : StatsShmemInit();
343 2032 : WaitEventCustomShmemInit();
344 2032 : InjectionPointShmemInit();
345 2032 : AioShmemInit();
346 2032 : }
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 1758 : InitializeShmemGUCs(void)
356 : {
357 : char buf[64];
358 : Size size_b;
359 : Size size_mb;
360 : Size hp_size;
361 : int num_semas;
362 :
363 : /*
364 : * Calculate the shared memory size and round up to the nearest megabyte.
365 : */
366 1758 : size_b = CalculateShmemSize(&num_semas);
367 1758 : size_mb = add_size(size_b, (1024 * 1024) - 1) / (1024 * 1024);
368 1758 : sprintf(buf, "%zu", size_mb);
369 1758 : SetConfigOption("shared_memory_size", buf,
370 : PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
371 :
372 : /*
373 : * Calculate the number of huge pages required.
374 : */
375 1758 : GetHugePageSize(&hp_size, NULL);
376 1758 : if (hp_size != 0)
377 : {
378 : Size hp_required;
379 :
380 1758 : hp_required = add_size(size_b / hp_size, 1);
381 1758 : sprintf(buf, "%zu", hp_required);
382 1758 : SetConfigOption("shared_memory_size_in_huge_pages", buf,
383 : PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
384 : }
385 :
386 1758 : sprintf(buf, "%d", num_semas);
387 1758 : SetConfigOption("num_os_semaphores", buf, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
388 1758 : }
|