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