public inbox for [email protected]
help / color / mirror / Atom feedFrom: Nathan Bossart <[email protected]>
To: [email protected]
Subject: reorganize "Shared Memory and LWLocks" section of docs
Date: Thu, 11 Jan 2024 22:14:30 -0600
Message-ID: <20240112041430.GA3557928@nathanxps13> (raw)
I recently began trying to write documentation for the dynamic shared
memory registry feature [0], and I noticed that the "Shared Memory and
LWLocks" section of the documentation might need some improvement. At
least, I felt that it would be hard to add any new content to this section
without making it very difficult to follow.
Concretely, I am proposing breaking it into two sections: one for shared
memory and one for LWLocks. Furthermore, the LWLocks section will be split
into two: one for requesting locks at server startup and one for requesting
locks after server startup. I intend to also split the shared memory
section into at-startup and after-startup sections if/when the dynamic
shared memory registry feature is committed.
Besides this restructuring, I felt that certain parts of this documentation
could benefit from rephrasing and/or additional detail.
Thoughts?
[0] https://postgr.es/m/20231205034647.GA2705267%40nathanxps13
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
[text/x-diff] v1-0001-reorganize-shared-memory-and-lwlocks-documentatio.patch (9.3K, ../20240112041430.GA3557928@nathanxps13/2-v1-0001-reorganize-shared-memory-and-lwlocks-documentatio.patch)
download | inline diff:
From dc5c1b37ced883021f4a92a17aa50b9d80d73fc6 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Thu, 11 Jan 2024 21:55:25 -0600
Subject: [PATCH v1 1/1] reorganize shared memory and lwlocks documentation
---
doc/src/sgml/xfunc.sgml | 180 +++++++++++++++++++++++++---------------
1 file changed, 112 insertions(+), 68 deletions(-)
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 89116ae74c..a758384a9a 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -3397,90 +3397,134 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
</sect2>
<sect2 id="xfunc-shared-addin">
- <title>Shared Memory and LWLocks</title>
+ <title>Shared Memory</title>
- <para>
- 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
- <xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
- The shared library should register a <literal>shmem_request_hook</literal>
- in its <function>_PG_init</function> function. This
- <literal>shmem_request_hook</literal> can reserve LWLocks or shared memory.
- Shared memory is reserved by calling:
+ <sect3 id="xfunc-shared-addin-at-startup">
+ <title>Requesting Shared Memory at Startup</title>
+
+ <para>
+ 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
+ <xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
+ The shared library should also register a
+ <literal>shmem_request_hook</literal> in its
+ <function>_PG_init</function> function. This
+ <literal>shmem_request_hook</literal> can reserve shared memory by
+ calling:
<programlisting>
void RequestAddinShmemSpace(int size)
</programlisting>
- from your <literal>shmem_request_hook</literal>.
- </para>
- <para>
- LWLocks are reserved by calling:
+ Each backend sould obtain a pointer to the reserved shared memory by
+ calling:
+<programlisting>
+void *ShmemInitStruct(const char *name, Size size, bool *foundPtr)
+</programlisting>
+ If this function sets <literal>foundPtr</literal> to
+ <literal>false</literal>, the caller should proceed to initialize the
+ contents of the reserved shared memory. If <literal>foundPtr</literal>
+ is set to <literal>true</literal>, the shared memory was already
+ initialized by another backend, and the caller need not initialize
+ further.
+ </para>
+
+ <para>
+ To avoid race conditions, each backend should use the LWLock
+ <function>AddinShmemInitLock</function> when initializing its allocation
+ of shared memory, as shown here:
+<programlisting>
+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);
+</programlisting>
+ <literal>shmem_startup_hook</literal> provides a convenient place for the
+ initialization code, but it is not strictly required that all such code
+ be placed in this hook. Any registered
+ <literal>shmem_startup_hook</literal> will be executed shortly after each
+ backend attaches to shared memory. Note that add-ins should still
+ acquire <function>AddinShmemInitLock</function> within this hook, as
+ shown in the example above.
+ </para>
+
+ <para>
+ An example of a <literal>shmem_request_hook</literal> and
+ <literal>shmem_startup_hook</literal> can be found in
+ <filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in
+ the <productname>PostgreSQL</productname> source tree.
+ </para>
+ </sect3>
+ </sect2>
+
+ <sect2 id="xfunc-addin-lwlocks">
+ <title>LWLocks</title>
+
+ <sect3 id="xfunc-addin-lwlocks-at-startup">
+ <title>Requesting LWLocks at Startup</title>
+
+ <para>
+ Add-ins can reserve LWLocks on server startup. Like with shared memory,
+ the add-in's shared library must be preloaded by specifying it in
+ <xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>,
+ and the shared library should register a
+ <literal>shmem_request_hook</literal> in its
+ <function>_PG_init</function> function. This
+ <literal>shmem_request_hook</literal> can reserve LWLocks by calling:
<programlisting>
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
</programlisting>
- from your <literal>shmem_request_hook</literal>. This will ensure that an array of
- <literal>num_lwlocks</literal> LWLocks is available under the name
- <literal>tranche_name</literal>. Use <function>GetNamedLWLockTranche</function>
- to get a pointer to this array.
- </para>
- <para>
- An example of a <literal>shmem_request_hook</literal> can be found in
- <filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in the
- <productname>PostgreSQL</productname> source tree.
- </para>
- <para>
- There is another, more flexible method of obtaining LWLocks. First,
- allocate a <literal>tranche_id</literal> from a shared counter by
- calling:
+ This ensures that an array of <literal>num_lwlocks</literal> LWLocks is
+ available under the name <literal>tranche_name</literal>. A pointer to
+ this array can be obtained by calling:
<programlisting>
-int LWLockNewTrancheId(void)
+LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
</programlisting>
- Next, each individual process using the <literal>tranche_id</literal>
- should associate it with a <literal>tranche_name</literal> by calling:
+ </para>
+ </sect3>
+
+ <sect3 id="xfunc-addin-lwlocks-after-startup">
+ <title>Requesting LWLocks After Startup</title>
+
+ <para>
+ There is another, more flexible method of obtaining LWLocks that can be
+ done after server startup and outside a
+ <literal>shmem_request_hook</literal>. To do so, first allocate a
+ <literal>tranche_id</literal> by calling:
<programlisting>
-void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
+int LWLockNewTrancheId(void)
</programlisting>
- It is also required to call <function>LWLockInitialize</function> once
- per LWLock, passing the <literal>tranche_id</literal> as argument:
+ Next, initialize each LWLock, passing the new
+ <literal>tranche_id</literal> as an argument:
<programlisting>
void LWLockInitialize(LWLock *lock, int tranche_id)
</programlisting>
- A complete usage example of <function>LWLockNewTrancheId</function>,
- <function>LWLockInitialize</function> and
- <function>LWLockRegisterTranche</function> can be found in
- <filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
- <productname>PostgreSQL</productname> source tree.
- </para>
- <para>
- To avoid possible race-conditions, each backend should use the LWLock
- <function>AddinShmemInitLock</function> when connecting to and initializing
- its allocation of shared memory, as shown here:
+ Finally, each backend using the <literal>tranche_id</literal> should
+ associate it with a <literal>tranche_name</literal> by calling:
<programlisting>
-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)
</programlisting>
- </para>
- <para>
- It is convenient to use <literal>shmem_startup_hook</literal> which allows
- placing all the code responsible for initializing shared memory in one
- place. When using <literal>shmem_startup_hook</literal> the extension
- still needs to acquire <function>AddinShmemInitLock</function> in order to
- work properly on all the supported platforms.
- </para>
+ Similar to shared memory, each backend should ensure that only one
+ process allocates a new <literal>tranche_id</literal>
+ (<function>LWLockNewTrancheId</function>) and initializes each new LWLock
+ (<function>LWLockInitialize</function>). One way to do this is to only
+ call these functions in your shared memory initialization code with the
+ <function>AddinShmemInitLock</function> held exclusively.
+ </para>
+
+ <para>
+ A complete usage example of <function>LWLockNewTrancheId</function>,
+ <function>LWLockInitialize</function>, and
+ <function>LWLockRegisterTranche</function> can be found in
+ <filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
+ <productname>PostgreSQL</productname> source tree.
+ </para>
+ </sect3>
</sect2>
<sect2 id="xfunc-addin-wait-events">
--
2.25.1
view thread (2+ messages)
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: reorganize "Shared Memory and LWLocks" section of docs
In-Reply-To: <20240112041430.GA3557928@nathanxps13>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox