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