@@ -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, &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>
34193480void 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>
34463505void 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, &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