diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index acf6ff74f98..1c0f39e11ec 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3628,7 +3628,7 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
Add-ins can reserve shared memory on server startup. To do so, the
add-in's shared library must be preloaded by specifying it in
shared_preload_libraries.
- The shared library should register callbacks in its
+ The shared library should register callbacks in
its _PG_init function, which then get called at the
right stages of the system startup to initialize the shared memory.
Here is an example:
@@ -3692,11 +3692,11 @@ my_shmem_init(void *arg)
}
- The request_fn callback is called during system
+ The shmem_request_fn callback is called during system
startup, before the shared memory has been allocated. It should call
ShmemRequestStruct() to register the add-in's
shared memory needs. Note that ShmemRequestStruct()
- doesn'' immediately allocate or initialize the memory, it merely
+ doesn't immediately allocate or initialize the memory, it merely
registers the space to be allocated later in the startup sequence. When
the memory is allocated, it is initialized to zero. To any more complex
initialization, set the init_fn() callback, which
@@ -3726,7 +3726,7 @@ my_shmem_init(void *arg)
libraries that are not specified in
shared_preload_libraries.
However, after startup the allocation can fail if there is not enough
- shared memory available. The system reserves a somes memory for
+ shared memory available. The system reserves some memory for
allocations after startup, but that reservation is small.
@@ -3739,8 +3739,8 @@ my_shmem_init(void *arg)
When RegisterShmemCallbacks() is called after
startup, it will immediately call the appropriate callbacks, depending
on whether the requested memory areas were already initialized by
- another backend. The callbacks will be held while holding an internal
- lock, which prevents concurrent two backends from initializating the
+ another backend. The callbacks will be called while holding an internal
+ lock, which prevents multiple backends from initializating the
memory area concurrently.
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index de843d03c50..cef16327263 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -27,7 +27,7 @@
*
* Shared memory areas should usually not be allocated after postmaster
* startup, although we do allow small allocations later for the benefit of
- * extension modules that loaded after startup. Despite that allowance,
+ * extension modules that are loaded after startup. Despite that allowance,
* extensions that need shared memory should be added in
* shared_preload_libraries, because the allowance is quite small and there is
* no guarantee that any memory is available after startup.
@@ -50,7 +50,7 @@
* -----
*
* To allocate shared memory, you need to register a set of callback functions
- * which handle the lifecycle of the allocation. In the register_fn
+ * which handle the lifecycle of the allocation. In the request_fn
* callback, fill in a ShmemStructDesc descriptor with the name, size, and any
* other options, and call ShmemRequestStruct(). Leave any unused fields as
* zeros.
@@ -90,12 +90,12 @@
* ---------
*
* Initializing shared memory happens in multiple phases. In the first phase,
- * during postmaster startup, all the shmem_request callbacks are called.
- * Only after all all the request callbacks have been called and all the shmem
- * areas have been requested by the ShmemRequestStruct() calls we know how
- * much shared memory we need in total. After that, postmaster allocates
- * global shared memory segment, and calls all the init_fn callbacks to
- * initialize all the requested shmem areas.
+ * during postmaster startup, all the shmem_request callbacks are called. Only
+ * after all the request callbacks have been called and all the shmem areas have
+ * been requested by the ShmemRequestStruct() calls we know how much shared
+ * memory we need in total. After that, postmaster allocates global shared
+ * memory segment, allocates memory to the requested areas, and calls all the
+ * init_fn callbacks to initialize all the requested shmem areas.
*
* In standard Unix-ish environments, individual backends do not need to
* re-establish their local pointers into shared memory, because they inherit
@@ -290,16 +290,12 @@ Datum pg_numa_available(PG_FUNCTION_ARGS);
void
ShmemRequestStruct(ShmemStructDesc *desc)
{
- ListCell *lc;
-
if (shmem_startup_state != SB_REQUESTING)
elog(ERROR, "ShmemRequestStruct can only be called from a shmem_request callback");
/* Check that it's not already registered in this process */
- foreach(lc, requested_shmem_areas)
+ foreach_ptr(ShmemStructDesc, existing, requested_shmem_areas)
{
- ShmemStructDesc *existing = (ShmemStructDesc *) lfirst(lc);
-
if (strcmp(existing->name, desc->name) == 0)
ereport(ERROR,
(errmsg("shared memory struct \"%s\" is already registered",
@@ -319,7 +315,6 @@ ShmemRequestStruct(ShmemStructDesc *desc)
size_t
ShmemGetRequestedSize(void)
{
- ListCell *lc;
size_t size;
/* memory needed for the ShmemIndex */
@@ -327,10 +322,8 @@ ShmemGetRequestedSize(void)
sizeof(ShmemIndexEnt));
/* memory needed for all the requested areas */
- foreach(lc, requested_shmem_areas)
+ foreach_ptr(ShmemStructDesc, desc, requested_shmem_areas)
{
- ShmemStructDesc *desc = (ShmemStructDesc *) lfirst(lc);
-
size = add_size(size, desc->size);
size = add_size(size, desc->extra_size);
}
@@ -358,12 +351,9 @@ ShmemInitRequested(void)
* Initialize all the requested memory areas. There are no concurrent
* processes yet, so no need for locking.
*/
- foreach(lc, requested_shmem_areas)
- {
- ShmemStructDesc *desc = (ShmemStructDesc *) lfirst(lc);
-
+ foreach_ptr(ShmemStructDesc, desc, requested_shmem_areas)
AttachOrInit(desc, true, false);
- }
+
list_free(requested_shmem_areas);
requested_shmem_areas = NIL;
@@ -465,24 +455,26 @@ AttachOrInit(ShmemStructDesc *desc, bool init_allowed, bool attach_allowed)
break;
}
}
- else if (!init_allowed)
- {
- /* attach was requested, but it was not found */
- ereport(FATAL,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("could not find ShmemIndex entry for data structure \"%s\"",
- desc->name)));
- }
- else if (!index_entry)
- {
- /* tried to add it to the hash table, but there was no space */
- ereport(ERROR,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("could not create ShmemIndex entry for data structure \"%s\"",
- desc->name)));
- }
else
{
+ if (!init_allowed)
+ {
+ /* The entry is not found and the caller expected it to be present. */
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("could not find ShmemIndex entry for data structure \"%s\"",
+ desc->name)));
+ }
+
+ if (!index_entry)
+ {
+ /* tried to add it to the hash table, but there was no space */
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("could not create ShmemIndex entry for data structure \"%s\"",
+ desc->name)));
+ }
+
/*
* We inserted the entry to the shared memory index. Allocate
* requested amount of shared memory for it, and do basic
@@ -729,7 +721,7 @@ ShmemAddrIsValid(const void *addr)
* backend startup, to allocate and initialize the area.
*
* This is normally called early during postmaster startup, but if the
- * SHMEM_ALLOW_AFTER_STARTUP is set, this can also be used after startup,
+ * SHMEM_CB_ALLOW_AFTER_STARTUP is set, this can also be used after startup,
* although after startup there's no guarantee that there's enough shared
* memory available. When called after startup, this immediately calls the
* right callbacks depending on whether another backend had already
@@ -744,7 +736,7 @@ RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
ListCell *lc;
bool found = false;
- if ((callbacks->flags & SHMEM_ALLOW_AFTER_STARTUP) == 0)
+ if ((callbacks->flags & SHMEM_CB_ALLOW_AFTER_STARTUP) == 0)
elog(ERROR, "FIXME: not allowed after startup");
Assert(requested_shmem_areas == NIL);
@@ -756,12 +748,8 @@ RegisterShmemCallbacks(const ShmemCallbacks *callbacks)
LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
- foreach(lc, requested_shmem_areas)
- {
- ShmemStructDesc *desc = (ShmemStructDesc *) lfirst(lc);
-
+ foreach_ptr(ShmemStructDesc, desc, requested_shmem_areas)
found = AttachOrInit(desc, true, true);
- }
/*
* FIXME: What to do if multiple shmem areas were requested, and some
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 720941e219e..a79d0a52528 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -62,10 +62,10 @@ typedef struct ShmemStructDesc
size_t extra_size;
/*
- * When the shmem area is initialized or attached to, pointer to it is
- * stored in *ptr. It usually points to a global variable, used to access
- * the shared memory area later. *ptr is set before the init_fn or
- * attach_fn callback is called.
+ * When the shmem area is initialized or attached to, pointer to it is stored
+ * in *ptr which is expected to point to a global variable, used to access
+ * the shared memory area later. *ptr is set before the init_fn or attach_fn
+ * callback is called.
*/
void **ptr;
} ShmemStructDesc;
@@ -127,6 +127,20 @@ typedef void (*ShmemRequestCallback) (void *arg);
typedef void (*ShmemInitCallback) (void *arg);
typedef void (*ShmemAttachCallback) (void *arg);
+
+/*
+ * Flags to control the behavior of RegisterShmemCallbacks().
+ *
+ * SHMEM_CB_ALLOW_AFTER_STARTUP: Allow these shared memory usages to be registered
+ * after postmaster startup. Normally, registering a shared memory system after
+ * postmaster startup is not allowed e.g. in an add-in library loaded on-demaind
+ * in a backend. If a subsystem sets this flag, the callbacks are called
+ * immediately after registration, to initialize or attach to the requested
+ * shared memory areas. This is not used by any built-in subsystems, but
+ * extensions can find it useful.
+ */
+#define SHMEM_CB_ALLOW_AFTER_STARTUP 0x00000001
+
/*
* Shared memory is reserved and allocated in stages at postmaster startup,
* and in EXEC_BACKEND mode, there's some extra work done to "attach" to them
@@ -135,7 +149,7 @@ typedef void (*ShmemAttachCallback) (void *arg);
*/
typedef struct ShmemCallbacks
{
- /* SHMEM_* flags */
+ /* SHMEM_CB_* flags */
int flags;
/*
@@ -164,18 +178,6 @@ typedef struct ShmemCallbacks
void *attach_fn_arg;
} ShmemCallbacks;
-/*
- * Allow these shared memory allocations after postmaster startup. Normally,
- * RegisterShmemCallbacks() errors out if it's called after postmaster startup
- * e.g. in an add-in library loaded on-demaind in a backend. If you set this
- * flag, RegisterShmemCallbacks() will instead immediately call the callbacks,
- * to initialize or attach to the requested shared memory areas.
- *
- * This is not used by any built-in subsystems, but extensions can find it
- * useful.
- */
-#define SHMEM_ALLOW_AFTER_STARTUP 0x00000001
-
/* shmem.c */
extern PGDLLIMPORT slock_t *ShmemLock;
typedef struct PGShmemHeader PGShmemHeader; /* avoid including