PostgreSQL Source Code git master
dsm_registry.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * dsm_registry.c
4 * Functions for interfacing with the dynamic shared memory registry.
5 *
6 * This provides a way for libraries to use shared memory without needing
7 * to request it at startup time via a shmem_request_hook. The registry
8 * stores dynamic shared memory (DSM) segment handles keyed by a
9 * library-specified string.
10 *
11 * The registry is accessed by calling GetNamedDSMSegment(). If a segment
12 * with the provided name does not yet exist, it is created and initialized
13 * with the provided init_callback callback function. Otherwise,
14 * GetNamedDSMSegment() simply ensures that the segment is attached to the
15 * current backend. This function guarantees that only one backend
16 * initializes the segment and that all other backends just attach it.
17 *
18 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
19 * Portions Copyright (c) 1994, Regents of the University of California
20 *
21 * IDENTIFICATION
22 * src/backend/storage/ipc/dsm_registry.c
23 *
24 *-------------------------------------------------------------------------
25 */
26
27#include "postgres.h"
28
29#include "lib/dshash.h"
31#include "storage/lwlock.h"
32#include "storage/shmem.h"
33#include "utils/memutils.h"
34
36{
40
42
43typedef struct DSMRegistryEntry
44{
45 char name[64];
47 size_t size;
49
51 offsetof(DSMRegistryEntry, handle),
52 sizeof(DSMRegistryEntry),
57};
58
61
62Size
64{
65 return MAXALIGN(sizeof(DSMRegistryCtxStruct));
66}
67
68void
70{
71 bool found;
72
74 ShmemInitStruct("DSM Registry Data",
76 &found);
77
78 if (!found)
79 {
82 }
83}
84
85/*
86 * Initialize or attach to the dynamic shared hash table that stores the DSM
87 * registry entries, if not already done. This must be called before accessing
88 * the table.
89 */
90static void
92{
93 /* Quick exit if we already did this. */
95 return;
96
97 /* Otherwise, use a lock to ensure only one process creates the table. */
98 LWLockAcquire(DSMRegistryLock, LW_EXCLUSIVE);
99
101 {
102 /* Initialize dynamic shared hash table for registry. */
107
108 /* Store handles in shared memory for other backends to use. */
111 }
112 else
113 {
114 /* Attach to existing dynamic shared hash table. */
118 DSMRegistryCtx->dshh, NULL);
119 }
120
121 LWLockRelease(DSMRegistryLock);
122}
123
124/*
125 * Initialize or attach a named DSM segment.
126 *
127 * This routine returns the address of the segment. init_callback is called to
128 * initialize the segment when it is first created.
129 */
130void *
131GetNamedDSMSegment(const char *name, size_t size,
132 void (*init_callback) (void *ptr), bool *found)
133{
134 DSMRegistryEntry *entry;
135 MemoryContext oldcontext;
136 void *ret;
137
138 Assert(found);
139
140 if (!name || *name == '\0')
142 (errmsg("DSM segment name cannot be empty")));
143
144 if (strlen(name) >= offsetof(DSMRegistryEntry, handle))
146 (errmsg("DSM segment name too long")));
147
148 if (size == 0)
150 (errmsg("DSM segment size must be nonzero")));
151
152 /* Be sure any local memory allocated by DSM/DSA routines is persistent. */
154
155 /* Connect to the registry. */
157
159 if (!(*found))
160 {
161 /* Initialize the segment. */
162 dsm_segment *seg = dsm_create(size, 0);
163
164 dsm_pin_segment(seg);
165 dsm_pin_mapping(seg);
166 entry->handle = dsm_segment_handle(seg);
167 entry->size = size;
168 ret = dsm_segment_address(seg);
169
170 if (init_callback)
171 (*init_callback) (ret);
172 }
173 else if (entry->size != size)
174 {
176 (errmsg("requested DSM segment size does not match size of "
177 "existing segment")));
178 }
179 else
180 {
181 dsm_segment *seg = dsm_find_mapping(entry->handle);
182
183 /* If the existing segment is not already attached, attach it now. */
184 if (seg == NULL)
185 {
186 seg = dsm_attach(entry->handle);
187 if (seg == NULL)
188 elog(ERROR, "could not map dynamic shared memory segment");
189
190 dsm_pin_mapping(seg);
191 }
192
193 ret = dsm_segment_address(seg);
194 }
195
197 MemoryContextSwitchTo(oldcontext);
198
199 return ret;
200}
#define MAXALIGN(LEN)
Definition: c.h:768
#define Assert(condition)
Definition: c.h:815
size_t Size
Definition: c.h:562
dsa_area * dsa_attach(dsa_handle handle)
Definition: dsa.c:510
void dsa_pin_mapping(dsa_area *area)
Definition: dsa.c:635
dsa_handle dsa_get_handle(dsa_area *area)
Definition: dsa.c:498
void dsa_pin(dsa_area *area)
Definition: dsa.c:975
dsm_handle dsa_handle
Definition: dsa.h:136
#define DSA_HANDLE_INVALID
Definition: dsa.h:139
#define dsa_create(tranch_id)
Definition: dsa.h:117
void dshash_strcpy(void *dest, const void *src, size_t size, void *arg)
Definition: dshash.c:622
void dshash_release_lock(dshash_table *hash_table, void *entry)
Definition: dshash.c:558
dshash_hash dshash_strhash(const void *v, size_t size, void *arg)
Definition: dshash.c:611
dshash_table_handle dshash_get_hash_table_handle(dshash_table *hash_table)
Definition: dshash.c:367
dshash_table * dshash_attach(dsa_area *area, const dshash_parameters *params, dshash_table_handle handle, void *arg)
Definition: dshash.c:270
int dshash_strcmp(const void *a, const void *b, size_t size, void *arg)
Definition: dshash.c:599
void * dshash_find_or_insert(dshash_table *hash_table, const void *key, bool *found)
Definition: dshash.c:433
dshash_table * dshash_create(dsa_area *area, const dshash_parameters *params, void *arg)
Definition: dshash.c:206
#define DSHASH_HANDLE_INVALID
Definition: dshash.h:27
dsa_pointer dshash_table_handle
Definition: dshash.h:24
dsm_handle dsm_segment_handle(dsm_segment *seg)
Definition: dsm.c:1123
void dsm_pin_mapping(dsm_segment *seg)
Definition: dsm.c:915
void dsm_pin_segment(dsm_segment *seg)
Definition: dsm.c:955
void * dsm_segment_address(dsm_segment *seg)
Definition: dsm.c:1095
dsm_segment * dsm_create(Size size, int flags)
Definition: dsm.c:516
dsm_segment * dsm_attach(dsm_handle h)
Definition: dsm.c:665
dsm_segment * dsm_find_mapping(dsm_handle handle)
Definition: dsm.c:1076
uint32 dsm_handle
Definition: dsm_impl.h:55
void DSMRegistryShmemInit(void)
Definition: dsm_registry.c:69
static void init_dsm_registry(void)
Definition: dsm_registry.c:91
static DSMRegistryCtxStruct * DSMRegistryCtx
Definition: dsm_registry.c:41
struct DSMRegistryEntry DSMRegistryEntry
static dshash_table * dsm_registry_table
Definition: dsm_registry.c:60
static dsa_area * dsm_registry_dsa
Definition: dsm_registry.c:59
static const dshash_parameters dsh_params
Definition: dsm_registry.c:50
struct DSMRegistryCtxStruct DSMRegistryCtxStruct
Size DSMRegistryShmemSize(void)
Definition: dsm_registry.c:63
void * GetNamedDSMSegment(const char *name, size_t size, void(*init_callback)(void *ptr), bool *found)
Definition: dsm_registry.c:131
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LWTRANCHE_DSM_REGISTRY_DSA
Definition: lwlock.h:208
@ LWTRANCHE_DSM_REGISTRY_HASH
Definition: lwlock.h:209
@ LW_EXCLUSIVE
Definition: lwlock.h:114
MemoryContext TopMemoryContext
Definition: mcxt.c:149
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
static pg_noinline void Size size
Definition: slab.c:607
dshash_table_handle dshh
Definition: dsm_registry.c:38
dsm_handle handle
Definition: dsm_registry.c:46
Definition: dsa.c:348
const char * name