@@ -3397,90 +3397,136 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
3397
3397
</sect2>
3398
3398
3399
3399
<sect2 id="xfunc-shared-addin">
3400
- <title>Shared Memory and LWLocks </title>
3400
+ <title>Shared Memory</title>
3401
3401
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:
3411
3414
<programlisting>
3412
- void RequestAddinShmemSpace(int size)
3415
+ void RequestAddinShmemSpace(Size size)
3413
3416
</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:
3418
3479
<programlisting>
3419
3480
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
3420
3481
</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:
3435
3485
<programlisting>
3436
- int LWLockNewTrancheId(void )
3486
+ LWLockPadded *GetNamedLWLockTranche(const char *tranche_name )
3437
3487
</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:
3440
3499
<programlisting>
3441
- void LWLockRegisterTranche( int tranche_id, const char *tranche_name )
3500
+ int LWLockNewTrancheId(void )
3442
3501
</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:
3445
3504
<programlisting>
3446
3505
void LWLockInitialize(LWLock *lock, int tranche_id)
3447
3506
</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>
3460
3513
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)
3475
3519
</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>
3484
3530
</sect2>
3485
3531
3486
3532
<sect2 id="xfunc-addin-wait-events">
0 commit comments