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