Skip to content

Commit 964152c

Browse files
doc: Reorganize section for shared memory and LWLocks.
Presently, this section meanders through a few different features, and the text itself is terse. This commit attempts to improve matters by splitting the section into smaller sections and by expanding the text for clarity. This is preparatory work for a follow-up commit that will introduce a way for libraries to use shared memory without needing to request it at startup time. Reviewed-by: Aleksander Alekseev, Bharath Rupireddy, Abhijit Menon-Sen Discussion: https://postgr.es/m/20240112041430.GA3557928%40nathanxps13 Discussion: https://postgr.es/m/20231205034647.GA2705267%40nathanxps13
1 parent 448a333 commit 964152c

File tree

1 file changed

+115
-69
lines changed

1 file changed

+115
-69
lines changed

doc/src/sgml/xfunc.sgml

+115-69
Original file line numberDiff line numberDiff line change
@@ -3397,90 +3397,136 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
33973397
</sect2>
33983398

33993399
<sect2 id="xfunc-shared-addin">
3400-
<title>Shared Memory and LWLocks</title>
3400+
<title>Shared Memory</title>
34013401

3402-
<para>
3403-
Add-ins can reserve LWLocks and an allocation of shared memory on server
3404-
startup. The add-in's shared library must be preloaded by specifying
3405-
it in
3406-
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
3407-
The shared library should register a <literal>shmem_request_hook</literal>
3408-
in its <function>_PG_init</function> function. This
3409-
<literal>shmem_request_hook</literal> can reserve LWLocks or shared memory.
3410-
Shared memory is reserved by calling:
3402+
<sect3 id="xfunc-shared-addin-at-startup">
3403+
<title>Requesting Shared Memory at Startup</title>
3404+
3405+
<para>
3406+
Add-ins can reserve shared memory on server startup. To do so, the
3407+
add-in's shared library must be preloaded by specifying it in
3408+
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>.
3409+
The shared library should also register a
3410+
<literal>shmem_request_hook</literal> in its
3411+
<function>_PG_init</function> function. This
3412+
<literal>shmem_request_hook</literal> can reserve shared memory by
3413+
calling:
34113414
<programlisting>
3412-
void RequestAddinShmemSpace(int size)
3415+
void RequestAddinShmemSpace(Size size)
34133416
</programlisting>
3414-
from your <literal>shmem_request_hook</literal>.
3415-
</para>
3416-
<para>
3417-
LWLocks are reserved by calling:
3417+
Each backend should obtain a pointer to the reserved shared memory by
3418+
calling:
3419+
<programlisting>
3420+
void *ShmemInitStruct(const char *name, Size size, bool *foundPtr)
3421+
</programlisting>
3422+
If this function sets <literal>foundPtr</literal> to
3423+
<literal>false</literal>, the caller should proceed to initialize the
3424+
contents of the reserved shared memory. If <literal>foundPtr</literal>
3425+
is set to <literal>true</literal>, the shared memory was already
3426+
initialized by another backend, and the caller need not initialize
3427+
further.
3428+
</para>
3429+
3430+
<para>
3431+
To avoid race conditions, each backend should use the LWLock
3432+
<function>AddinShmemInitLock</function> when initializing its allocation
3433+
of shared memory, as shown here:
3434+
<programlisting>
3435+
static mystruct *ptr = NULL;
3436+
bool found;
3437+
3438+
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
3439+
ptr = ShmemInitStruct("my struct name", size, &amp;found);
3440+
if (!found)
3441+
{
3442+
... initialize contents of shared memory ...
3443+
ptr->locks = GetNamedLWLockTranche("my tranche name");
3444+
}
3445+
LWLockRelease(AddinShmemInitLock);
3446+
</programlisting>
3447+
<literal>shmem_startup_hook</literal> provides a convenient place for the
3448+
initialization code, but it is not strictly required that all such code
3449+
be placed in this hook. Each backend will execute the registered
3450+
<literal>shmem_startup_hook</literal> shortly after it attaches to shared
3451+
memory. Note that add-ins should still acquire
3452+
<function>AddinShmemInitLock</function> within this hook, as shown in the
3453+
example above.
3454+
</para>
3455+
3456+
<para>
3457+
An example of a <literal>shmem_request_hook</literal> and
3458+
<literal>shmem_startup_hook</literal> can be found in
3459+
<filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in
3460+
the <productname>PostgreSQL</productname> source tree.
3461+
</para>
3462+
</sect3>
3463+
</sect2>
3464+
3465+
<sect2 id="xfunc-addin-lwlocks">
3466+
<title>LWLocks</title>
3467+
3468+
<sect3 id="xfunc-addin-lwlocks-at-startup">
3469+
<title>Requesting LWLocks at Startup</title>
3470+
3471+
<para>
3472+
Add-ins can reserve LWLocks on server startup. As with shared memory,
3473+
the add-in's shared library must be preloaded by specifying it in
3474+
<xref linkend="guc-shared-preload-libraries"/><indexterm><primary>shared_preload_libraries</primary></indexterm>,
3475+
and the shared library should register a
3476+
<literal>shmem_request_hook</literal> in its
3477+
<function>_PG_init</function> function. This
3478+
<literal>shmem_request_hook</literal> can reserve LWLocks by calling:
34183479
<programlisting>
34193480
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
34203481
</programlisting>
3421-
from your <literal>shmem_request_hook</literal>. This will ensure that an array of
3422-
<literal>num_lwlocks</literal> LWLocks is available under the name
3423-
<literal>tranche_name</literal>. Use <function>GetNamedLWLockTranche</function>
3424-
to get a pointer to this array.
3425-
</para>
3426-
<para>
3427-
An example of a <literal>shmem_request_hook</literal> can be found in
3428-
<filename>contrib/pg_stat_statements/pg_stat_statements.c</filename> in the
3429-
<productname>PostgreSQL</productname> source tree.
3430-
</para>
3431-
<para>
3432-
There is another, more flexible method of obtaining LWLocks. First,
3433-
allocate a <literal>tranche_id</literal> from a shared counter by
3434-
calling:
3482+
This ensures that an array of <literal>num_lwlocks</literal> LWLocks is
3483+
available under the name <literal>tranche_name</literal>. A pointer to
3484+
this array can be obtained by calling:
34353485
<programlisting>
3436-
int LWLockNewTrancheId(void)
3486+
LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
34373487
</programlisting>
3438-
Next, each individual process using the <literal>tranche_id</literal>
3439-
should associate it with a <literal>tranche_name</literal> by calling:
3488+
</para>
3489+
</sect3>
3490+
3491+
<sect3 id="xfunc-addin-lwlocks-after-startup">
3492+
<title>Requesting LWLocks After Startup</title>
3493+
3494+
<para>
3495+
There is another, more flexible method of obtaining LWLocks that can be
3496+
done after server startup and outside a
3497+
<literal>shmem_request_hook</literal>. To do so, first allocate a
3498+
<literal>tranche_id</literal> by calling:
34403499
<programlisting>
3441-
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
3500+
int LWLockNewTrancheId(void)
34423501
</programlisting>
3443-
It is also required to call <function>LWLockInitialize</function> once
3444-
per LWLock, passing the <literal>tranche_id</literal> as argument:
3502+
Next, initialize each LWLock, passing the new
3503+
<literal>tranche_id</literal> as an argument:
34453504
<programlisting>
34463505
void LWLockInitialize(LWLock *lock, int tranche_id)
34473506
</programlisting>
3448-
A complete usage example of <function>LWLockNewTrancheId</function>,
3449-
<function>LWLockInitialize</function> and
3450-
<function>LWLockRegisterTranche</function> can be found in
3451-
<filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
3452-
<productname>PostgreSQL</productname> source tree.
3453-
</para>
3454-
<para>
3455-
To avoid possible race-conditions, each backend should use the LWLock
3456-
<function>AddinShmemInitLock</function> when connecting to and initializing
3457-
its allocation of shared memory, as shown here:
3458-
<programlisting>
3459-
static mystruct *ptr = NULL;
3507+
Similar to shared memory, each backend should ensure that only one
3508+
process allocates a new <literal>tranche_id</literal> and initializes
3509+
each new LWLock. One way to do this is to only call these functions in
3510+
your shared memory initialization code with the
3511+
<function>AddinShmemInitLock</function> held exclusively.
3512+
</para>
34603513

3461-
if (!ptr)
3462-
{
3463-
bool found;
3464-
3465-
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
3466-
ptr = ShmemInitStruct("my struct name", size, &amp;found);
3467-
if (!found)
3468-
{
3469-
initialize contents of shmem area;
3470-
acquire any requested LWLocks using:
3471-
ptr->locks = GetNamedLWLockTranche("my tranche name");
3472-
}
3473-
LWLockRelease(AddinShmemInitLock);
3474-
}
3514+
<para>
3515+
Finally, each backend using the <literal>tranche_id</literal> should
3516+
associate it with a <literal>tranche_name</literal> by calling:
3517+
<programlisting>
3518+
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
34753519
</programlisting>
3476-
</para>
3477-
<para>
3478-
It is convenient to use <literal>shmem_startup_hook</literal> which allows
3479-
placing all the code responsible for initializing shared memory in one
3480-
place. When using <literal>shmem_startup_hook</literal> the extension
3481-
still needs to acquire <function>AddinShmemInitLock</function> in order to
3482-
work properly on all the supported platforms.
3483-
</para>
3520+
</para>
3521+
3522+
<para>
3523+
A complete usage example of <function>LWLockNewTrancheId</function>,
3524+
<function>LWLockInitialize</function>, and
3525+
<function>LWLockRegisterTranche</function> can be found in
3526+
<filename>contrib/pg_prewarm/autoprewarm.c</filename> in the
3527+
<productname>PostgreSQL</productname> source tree.
3528+
</para>
3529+
</sect3>
34843530
</sect2>
34853531

34863532
<sect2 id="xfunc-addin-wait-events">

0 commit comments

Comments
 (0)