current
backend.
</para>
<para>
Unlike shared memory reserved at server startup, there is no need to
acquire <function>AddinShmemInitLock</function> or otherwise take action
to avoid race conditions when reserving shared memory with
<function>GetNamedDSMSegment</function>. This function ensures that only
one backend allocates and initializes the segment and that all other
backends receive a pointer to the fully allocated and initialized
segment.
</para>
<para>
A complete usage example of <function>GetNamedDSMSegment</function> can
be found in
<filename>src/test/modules/test_dsm_registry/test_dsm_registry.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. As with shared memory
reserved at 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>,
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>
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>
LWLockPadded *GetNamedLWLockTranche(const char *tranche_name)
</programlisting>
</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>
int LWLockNewTrancheId(void)
</programlisting>
Next, initialize each LWLock, passing the new
<literal>tranche_id</literal> as an argument:
<programlisting>
void LWLockInitialize(LWLock *lock, int tranche_id)
</programlisting>
Similar to shared memory, each backend should ensure that only one
process allocates a new <literal>tranche_id</literal> and initializes
each new LWLock. One way to do this is to only call these functions in
your shared memory initialization code with the
<function>AddinShmemInitLock</function> held exclusively. If using
<function>GetNamedDSMSegment</function>, calling these functions in the
<function>init_callback</function> callback function is sufficient to
avoid race conditions.
</para>
<para>
Finally, each backend using the <literal>tranche_id</literal> should
associate it with a <literal>tranche_name</literal> by calling:
<programlisting>
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
</programlisting>
</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">
<title>Custom Wait Events</title>
<para>
Add-ins can define custom wait events under the wait event type
<literal>Extension</literal> by calling:
<programlisting>
uint32 WaitEventExtensionNew(const