/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 | } |