diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 89116ae74c..ede2a5dea6 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3397,90 +3397,136 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
- Shared Memory and LWLocks
+ Shared Memory
-
- Add-ins can reserve LWLocks and an allocation of shared memory on server
- startup. The add-in's shared library must be preloaded by specifying
- it in
- shared_preload_libraries.
- The shared library should register a shmem_request_hook
- in its _PG_init function. This
- shmem_request_hook can reserve LWLocks or shared memory.
- Shared memory is reserved by calling:
+
+ Requesting Shared Memory at Startup
+
+
+ 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 also register a
+ shmem_request_hook in its
+ _PG_init function. This
+ shmem_request_hook can reserve shared memory by
+ calling:
-void RequestAddinShmemSpace(int size)
+void RequestAddinShmemSpace(Size size)
- from your shmem_request_hook.
-
-
- LWLocks are reserved by calling:
+ Each backend should obtain a pointer to the reserved shared memory by
+ calling:
+
+void *ShmemInitStruct(const char *name, Size size, bool *foundPtr)
+
+ If this function sets foundPtr to
+ false, the caller should proceed to initialize the
+ contents of the reserved shared memory. If foundPtr
+ is set to true, the shared memory was already
+ initialized by another backend, and the caller need not initialize
+ further.
+
+
+
+ To avoid race conditions, each backend should use the LWLock
+ AddinShmemInitLock when initializing its allocation
+ of shared memory, as shown here:
+
+static mystruct *ptr = NULL;
+bool found;
+
+LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
+ptr = ShmemInitStruct("my struct name", size, &found);
+if (!found)
+{
+ ... initialize contents of shared memory ...
+ ptr->locks = GetNamedLWLockTranche("my tranche name");
+}
+LWLockRelease(AddinShmemInitLock);
+
+ shmem_startup_hook provides a convenient place for the
+ initialization code, but it is not strictly required that all such code
+ be placed in this hook. Each backend will execute the registered
+ shmem_startup_hook shortly after it attaches to shared
+ memory. Note that add-ins should still acquire
+ AddinShmemInitLock within this hook, as shown in the
+ example above.
+
+
+
+ An example of a shmem_request_hook and
+ shmem_startup_hook can be found in
+ contrib/pg_stat_statements/pg_stat_statements.c in
+ the PostgreSQL source tree.
+
+
+
+
+
+ LWLocks
+
+
+ Requesting LWLocks at Startup
+
+
+ Add-ins can reserve LWLocks on server startup. As with shared memory,
+ the add-in's shared library must be preloaded by specifying it in
+ shared_preload_libraries,
+ and the shared library should register a
+ shmem_request_hook in its
+ _PG_init function. This
+ shmem_request_hook can reserve LWLocks by calling:
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
- from your shmem_request_hook. This will ensure that an array of
- num_lwlocks LWLocks is available under the name
- tranche_name. Use GetNamedLWLockTranche
- to get a pointer to this array.
-
-
- An example of a shmem_request_hook can be found in
- contrib/pg_stat_statements/pg_stat_statements.c in the
- PostgreSQL source tree.
-
-
- There is another, more flexible method of obtaining LWLocks. First,
- allocate a tranche_id from a shared counter by
- calling:
+ This ensures that an array of num_lwlocks LWLocks is
+ available under the name tranche_name. A pointer to
+ this array can be obtained by calling:
+
+LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
+
+
+
+
+
+ Requesting LWLocks After Startup
+
+
+ There is another, more flexible method of obtaining LWLocks that can be
+ done after server startup and outside a
+ shmem_request_hook. To do so, first allocate a
+ tranche_id by calling:
int LWLockNewTrancheId(void)
- Next, each individual process using the tranche_id
- should associate it with a tranche_name by calling:
-
-void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
-
- It is also required to call LWLockInitialize once
- per LWLock, passing the tranche_id as argument:
+ Next, initialize each LWLock, passing the new
+ tranche_id as an argument:
void LWLockInitialize(LWLock *lock, int tranche_id)
- A complete usage example of LWLockNewTrancheId,
- LWLockInitialize and
- LWLockRegisterTranche can be found in
- contrib/pg_prewarm/autoprewarm.c in the
- PostgreSQL source tree.
-
-
- To avoid possible race-conditions, each backend should use the LWLock
- AddinShmemInitLock when connecting to and initializing
- its allocation of shared memory, as shown here:
+ Similar to shared memory, each backend should ensure that only one
+ process allocates a new tranche_id and initializes
+ each new LWLock. One way to do this is to only call these functions in
+ your shared memory initialization code with the
+ AddinShmemInitLock held exclusively.
+
+
+
+ Finally, each backend using the tranche_id should
+ associate it with a tranche_name by calling:
-static mystruct *ptr = NULL;
-
-if (!ptr)
-{
- bool found;
-
- LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
- ptr = ShmemInitStruct("my struct name", size, &found);
- if (!found)
- {
- initialize contents of shmem area;
- acquire any requested LWLocks using:
- ptr->locks = GetNamedLWLockTranche("my tranche name");
- }
- LWLockRelease(AddinShmemInitLock);
-}
+void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
-
-
- It is convenient to use shmem_startup_hook which allows
- placing all the code responsible for initializing shared memory in one
- place. When using shmem_startup_hook the extension
- still needs to acquire AddinShmemInitLock in order to
- work properly on all the supported platforms.
-
+
+
+
+ A complete usage example of LWLockNewTrancheId,
+ LWLockInitialize, and
+ LWLockRegisterTranche can be found in
+ contrib/pg_prewarm/autoprewarm.c in the
+ PostgreSQL source tree.
+
+