reserve shared memory by
calling:
<programlisting>
void RequestAddinShmemSpace(Size size)
</programlisting>
Each backend should 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. Each backend will execute the registered
<literal>shmem_startup_hook</literal> shortly after it 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>
<sect3 id="xfunc-shared-addin-after-startup">
<title>Requesting Shared Memory After Startup</title>
<para>
There is another, more flexible method of reserving shared memory that
can be done after server startup and outside a
<literal>shmem_request_hook</literal>. To do so, each backend that will
use the shared memory should obtain a pointer to it by calling:
<programlisting>
void *GetNamedDSMSegment(const char *name, size_t size,
void (*init_callback) (void *ptr),
bool *found)
</programlisting>
If a dynamic shared memory segment with the given name does not yet
exist, this function will allocate it and initialize it with the provided
<function>init_callback</function> callback function. If the segment has
already been allocated and initialized by another backend, this function
simply attaches the existing dynamic shared memory segment to the 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