1/*-------------------------------------------------------------------------
4 * shared memory segment table of contents
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * src/backend/storage/ipc/shm_toc.c
11 *-------------------------------------------------------------------------
29 slock_t
toc_mutex;
/* Spinlock for mutual exclusion */
37 * Initialize a region of shared memory with a table of contents.
49 * The alignment code in shm_toc_allocate() assumes that the starting
50 * value is buffer-aligned.
60 * Attach to an existing table of contents. If the magic number found at
61 * the target address doesn't match our expectations, return NULL.
78 * Allocate shared memory from a segment managed by a table of contents.
80 * This is not a full-blown allocator; there's no way to free memory. It's
81 * just a way of dividing a single physical shared memory segment into logical
82 * chunks that may be used for different purposes.
84 * We allocate backwards from the end of the segment, so that the TOC entries
85 * can grow forward from the start of the segment.
97 * Make sure request is well-aligned. XXX: MAXALIGN is not enough,
98 * because atomic ops might need a wider alignment. We don't have a
99 * proper definition for the minimum to make atomic ops safe, but
100 * BUFFERALIGN ought to be enough.
112 /* Check for memory exhaustion and overflow. */
113 if (toc_bytes + nbytes > total_bytes || toc_bytes + nbytes < toc_bytes)
117 (
errcode(ERRCODE_OUT_OF_MEMORY),
118 errmsg(
"out of shared memory")));
124 return ((
char *) toc) + (total_bytes - allocated_bytes - nbytes);
128 * Return the number of bytes that can still be allocated.
135 Size allocated_bytes;
147 return total_bytes - (allocated_bytes +
BUFFERALIGN(toc_bytes));
151 * Insert a TOC entry.
153 * The idea here is that the process setting up the shared memory segment will
154 * register the addresses of data structures within the segment using this
155 * function. Each data structure will be identified using a 64-bit key, which
156 * is assumed to be a well-known or discoverable integer. Other processes
157 * accessing the shared memory segment can pass the same key to
158 * shm_toc_lookup() to discover the addresses of those data structures.
160 * Since the shared memory segment may be mapped at different addresses within
161 * different backends, we store relative rather than absolute pointers.
163 * This won't scale well to a large number of keys. Hopefully, that isn't
164 * necessary; if it proves to be, we might need to provide a more sophisticated
165 * data structure here. But the real idea here is just to give someone mapping
166 * a dynamic shared memory the ability to find the bare minimum number of
167 * pointers that they need to bootstrap. If you're storing a lot of stuff in
168 * the TOC, you're doing it wrong.
175 Size allocated_bytes;
180 /* Relativize pointer. */
181 Assert(address > (
void *) toc);
182 offset = ((
char *) address) - (
char *) toc;
192 /* Check for memory exhaustion and overflow. */
199 (
errcode(ERRCODE_OUT_OF_MEMORY),
200 errmsg(
"out of shared memory")));
203 Assert(offset < total_bytes);
208 * By placing a write barrier after filling in the entry and before
209 * updating the number of entries, we make it safe to read the TOC
220 * Look up a TOC entry.
222 * If the key is not found, returns NULL if noError is true, otherwise
223 * throws elog(ERROR).
225 * Unlike the other functions in this file, this operation acquires no lock;
226 * it uses only barriers. It probably wouldn't hurt concurrency very much even
227 * if it did get a lock, but since it's reasonably likely that a group of
228 * worker processes could each read a series of entries from the same TOC
229 * right around the same time, there seems to be some value in avoiding it.
238 * Read the number of entries before we examine any entry. We assume that
239 * reading a uint32 is atomic.
244 /* Now search for a matching entry. */
245 for (
i = 0;
i < nentry; ++
i)
248 return ((
char *) toc) + toc->toc_entry[
i].offset;
251 /* No matching entry was found. */
259 * Estimate how much shared memory will be required to store a TOC and its
260 * dependent data structures.
267 sz = offsetof(
shm_toc, toc_entry);
#define pg_read_barrier()
#define pg_write_barrier()
#define BUFFERALIGN_DOWN(LEN)
#define FLEXIBLE_ARRAY_MEMBER
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
struct shm_toc_entry shm_toc_entry
void * shm_toc_allocate(shm_toc *toc, Size nbytes)
Size shm_toc_estimate(shm_toc_estimator *e)
shm_toc * shm_toc_create(uint64 magic, void *address, Size nbytes)
Size shm_toc_freespace(shm_toc *toc)
void shm_toc_insert(shm_toc *toc, uint64 key, void *address)
void * shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
shm_toc * shm_toc_attach(uint64 magic, void *address)
Size add_size(Size s1, Size s2)
Size mul_size(Size s1, Size s2)
#define SpinLockInit(lock)
#define SpinLockRelease(lock)
#define SpinLockAcquire(lock)
shm_toc_entry toc_entry[FLEXIBLE_ARRAY_MEMBER]