1 /*-------------------------------------------------------------------------
4 * create shared memory and initialize shared memory data structures.
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/storage/ipc/shmem.c,v 1.102 2009/01/01 17:23:47 momjian Exp $
13 *-------------------------------------------------------------------------
16 * POSTGRES processes share one or more regions of shared memory.
17 * The shared memory is created by a postmaster and is inherited
18 * by each backend via fork() (or, in some ports, via other OS-specific
19 * methods). The routines in this file are used for allocating and
20 * binding to shared memory data structures.
23 * (a) There are three kinds of shared memory data structures
24 * available to POSTGRES: fixed-size structures, queues and hash
25 * tables. Fixed-size structures contain things like global variables
26 * for a module and should never be allocated after the shared memory
27 * initialization phase. Hash tables have a fixed maximum size, but
28 * their actual size can vary dynamically. When entries are added
29 * to the table, more space is allocated. Queues link data structures
30 * that have been allocated either within fixed-size structures or as hash
31 * buckets. Each shared data structure has a string name to identify
32 * it (assigned in the module that declares it).
34 * (b) During initialization, each module looks for its
35 * shared data structures in a hash table called the "Shmem Index".
36 * If the data structure is not present, the caller can allocate
37 * a new one and initialize it. If the data structure is present,
38 * the caller "attaches" to the structure by initializing a pointer
39 * in the local address space.
40 * The shmem index has two purposes: first, it gives us
41 * a simple model of how the world looks when a backend process
42 * initializes. If something is present in the shmem index,
43 * it is initialized. If it is not, it is uninitialized. Second,
44 * the shmem index allows us to allocate shared memory on demand
45 * instead of trying to preallocate structures and hard-wire the
46 * sizes and locations in header files. If you are using a lot
47 * of shared memory in a lot of different places (and changing
48 * things during development), this is important.
50 * (c) In standard Unix-ish environments, individual backends do not
51 * need to re-establish their local pointers into shared memory, because
52 * they inherit correct values of those variables via fork() from the
53 * postmaster. However, this does not work in the EXEC_BACKEND case.
54 * In ports using EXEC_BACKEND, new backends have to set up their local
55 * pointers using the method described in (b) above.
57 * (d) memory allocation model: shared memory can never be
58 * freed, once allocated. Each hash table has its own free list,
59 * so hash buckets can be reused when an item is deleted. However,
60 * if one hash table grows very large and then shrinks, its space
61 * cannot be redistributed to other tables. We could build a simple
62 * hash bucket garbage collector if need be. Right now, it seems
68 #include "access/transam.h"
69 #include "miscadmin.h"
70 #include "storage/lwlock.h"
71 #include "storage/pg_shmem.h"
72 #include "storage/shmem.h"
73 #include "storage/spin.h"
76 /* shared memory global variables */
78 static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
80 static void *ShmemBase; /* start address of shared memory */
82 static void *ShmemEnd; /* end+1 address of shared memory */
84 slock_t *ShmemLock; /* spinlock for shared memory and LWLock
87 static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
91 * InitShmemAccess() --- set up basic pointers to shared memory.
93 * Note: the argument should be declared "PGShmemHeader *seghdr",
94 * but we use void to avoid having to include ipc.h in shmem.h.
97 InitShmemAccess(void *seghdr)
99 PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;
101 ShmemSegHdr = shmhdr;
102 ShmemBase = (void *) shmhdr;
103 ShmemEnd = (char *) ShmemBase + shmhdr->totalsize;
107 * InitShmemAllocation() --- set up shared-memory space allocation.
109 * This should be called only in the postmaster or a standalone backend.
112 InitShmemAllocation(void)
114 PGShmemHeader *shmhdr = ShmemSegHdr;
116 Assert(shmhdr != NULL);
119 * Initialize the spinlock used by ShmemAlloc. We have to do the space
120 * allocation the hard way, since obviously ShmemAlloc can't be called
123 ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
124 shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
125 Assert(shmhdr->freeoffset <= shmhdr->totalsize);
127 SpinLockInit(ShmemLock);
129 /* ShmemIndex can't be set up yet (need LWLocks first) */
130 shmhdr->index = NULL;
131 ShmemIndex = (HTAB *) NULL;
134 * Initialize ShmemVariableCache for transaction manager. (This doesn't
135 * really belong here, but not worth moving.)
137 ShmemVariableCache = (VariableCache)
138 ShmemAlloc(sizeof(*ShmemVariableCache));
139 memset(ShmemVariableCache, 0, sizeof(*ShmemVariableCache));
143 * ShmemAlloc -- allocate max-aligned chunk from shared memory
145 * Assumes ShmemLock and ShmemSegHdr are initialized.
147 * Returns: real pointer to memory or NULL if we are out
148 * of space. Has to return a real pointer in order
149 * to be compatible with malloc().
152 ShmemAlloc(Size size)
158 /* use volatile pointer to prevent code rearrangement */
159 volatile PGShmemHeader *shmemseghdr = ShmemSegHdr;
162 * ensure all space is adequately aligned.
164 size = MAXALIGN(size);
166 Assert(shmemseghdr != NULL);
168 SpinLockAcquire(ShmemLock);
170 newStart = shmemseghdr->freeoffset;
172 /* extra alignment for large requests, since they are probably buffers */
174 newStart = BUFFERALIGN(newStart);
176 newFree = newStart + size;
177 if (newFree <= shmemseghdr->totalsize)
179 newSpace = (void *) ((char *) ShmemBase + newStart);
180 shmemseghdr->freeoffset = newFree;
185 SpinLockRelease(ShmemLock);
189 (errcode(ERRCODE_OUT_OF_MEMORY),
190 errmsg("out of shared memory")));
196 * ShmemAddrIsValid -- test if an address refers to shared memory
198 * Returns TRUE if the pointer points within the shared memory segment.
201 ShmemAddrIsValid(void *addr)
203 return (addr >= ShmemBase) && (addr < ShmemEnd);
207 * InitShmemIndex() --- set up or attach to shmem index table.
216 * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
217 * hashtable to exist already, we have a bit of a circularity problem in
218 * initializing the ShmemIndex itself. The special "ShmemIndex" hash
219 * table name will tell ShmemInitStruct to fake it.
222 /* create the shared memory shmem index */
223 info.keysize = SHMEM_INDEX_KEYSIZE;
224 info.entrysize = sizeof(ShmemIndexEnt);
225 hash_flags = HASH_ELEM;
227 ShmemIndex = ShmemInitHash("ShmemIndex",
228 SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
231 elog(FATAL, "could not initialize Shmem Index");
235 * ShmemInitHash -- Create and initialize, or attach to, a
236 * shared memory hash table.
238 * We assume caller is doing some kind of synchronization
239 * so that two people don't try to create/initialize the
242 * max_size is the estimated maximum number of hashtable entries. This is
243 * not a hard limit, but the access efficiency will degrade if it is
244 * exceeded substantially (since it's used to compute directory size and
245 * the hash table buckets will get overfull).
247 * init_size is the number of hashtable entries to preallocate. For a table
248 * whose maximum size is certain, this should be equal to max_size; that
249 * ensures that no run-time out-of-shared-memory failures can occur.
252 ShmemInitHash(const char *name, /* table string name for shmem index */
253 long init_size, /* initial table size */
254 long max_size, /* max size of the table */
255 HASHCTL *infoP, /* info about key and bucket size */
256 int hash_flags) /* info about infoP */
262 * Hash tables allocated in shared memory have a fixed directory; it can't
263 * grow or other backends wouldn't be able to find it. So, make sure we
264 * make it big enough to start with.
266 * The shared memory allocator must be specified too.
268 infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);
269 infoP->alloc = ShmemAlloc;
270 hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
272 /* look it up in the shmem index */
273 location = ShmemInitStruct(name,
274 hash_get_shared_size(infoP, hash_flags),
278 * If fail, shmem index is corrupted. Let caller give the error message
279 * since it has more information
281 if (location == NULL)
285 * if it already exists, attach to it rather than allocate and initialize
289 hash_flags |= HASH_ATTACH;
291 /* Pass location of hashtable header to hash_create */
292 infoP->hctl = (HASHHDR *) location;
294 return hash_create(name, init_size, infoP, hash_flags);
298 * ShmemInitStruct -- Create/attach to a structure in shared
301 * This is called during initialization to find or allocate
302 * a data structure in shared memory. If no other process
303 * has created the structure, this routine allocates space
304 * for it. If it exists already, a pointer to the existing
307 * Returns: real pointer to the object. FoundPtr is TRUE if
308 * the object is already in the shmem index (hence, already
312 ShmemInitStruct(const char *name, Size size, bool *foundPtr)
314 ShmemIndexEnt *result;
317 LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
321 PGShmemHeader *shmemseghdr = ShmemSegHdr;
323 Assert(strcmp(name, "ShmemIndex") == 0);
324 if (IsUnderPostmaster)
326 /* Must be initializing a (non-standalone) backend */
327 Assert(shmemseghdr->index != NULL);
328 structPtr = shmemseghdr->index;
334 * If the shmem index doesn't exist, we are bootstrapping: we must
335 * be trying to init the shmem index itself.
337 * Notice that the ShmemIndexLock is released before the shmem
338 * index has been initialized. This should be OK because no other
339 * process can be accessing shared memory yet.
341 Assert(shmemseghdr->index == NULL);
342 structPtr = ShmemAlloc(size);
343 shmemseghdr->index = structPtr;
346 LWLockRelease(ShmemIndexLock);
350 /* look it up in the shmem index */
351 result = (ShmemIndexEnt *)
352 hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr);
356 LWLockRelease(ShmemIndexLock);
358 (errcode(ERRCODE_OUT_OF_MEMORY),
359 errmsg("out of shared memory")));
365 * Structure is in the shmem index so someone else has allocated it
366 * already. The size better be the same as the size we are trying to
367 * initialize to or there is a name conflict (or worse).
369 if (result->size != size)
371 LWLockRelease(ShmemIndexLock);
373 elog(WARNING, "ShmemIndex entry size is wrong");
374 /* let caller print its message too */
377 structPtr = result->location;
381 /* It isn't in the table yet. allocate and initialize it */
382 structPtr = ShmemAlloc(size);
387 hash_search(ShmemIndex, name, HASH_REMOVE, NULL);
388 LWLockRelease(ShmemIndexLock);
391 (errcode(ERRCODE_OUT_OF_MEMORY),
392 errmsg("could not allocate shared memory segment \"%s\"",
398 result->location = structPtr;
400 Assert(ShmemAddrIsValid(structPtr));
402 LWLockRelease(ShmemIndexLock);
408 * Add two Size values, checking for overflow
411 add_size(Size s1, Size s2)
416 /* We are assuming Size is an unsigned type here... */
417 if (result < s1 || result < s2)
419 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
420 errmsg("requested shared memory size overflows size_t")));
425 * Multiply two Size values, checking for overflow
428 mul_size(Size s1, Size s2)
432 if (s1 == 0 || s2 == 0)
435 /* We are assuming Size is an unsigned type here... */
436 if (result / s2 != s1)
438 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
439 errmsg("requested shared memory size overflows size_t")));