PostgreSQL Source Code git master
Loading...
Searching...
No Matches
lwlock.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * lwlock.c
4 * Lightweight lock manager
5 *
6 * Lightweight locks are intended primarily to provide mutual exclusion of
7 * access to shared-memory data structures. Therefore, they offer both
8 * exclusive and shared lock modes (to support read/write and read-only
9 * access to a shared object). There are few other frammishes. User-level
10 * locking should be done with the full lock manager --- which depends on
11 * LWLocks to protect its shared state.
12 *
13 * In addition to exclusive and shared modes, lightweight locks can be used to
14 * wait until a variable changes value. The variable is initially not set
15 * when the lock is acquired with LWLockAcquire, i.e. it remains set to the
16 * value it was set to when the lock was released last, and can be updated
17 * without releasing the lock by calling LWLockUpdateVar. LWLockWaitForVar
18 * waits for the variable to be updated, or until the lock is free. When
19 * releasing the lock with LWLockReleaseClearVar() the value can be set to an
20 * appropriate value for a free lock. The meaning of the variable is up to
21 * the caller, the lightweight lock code just assigns and compares it.
22 *
23 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
24 * Portions Copyright (c) 1994, Regents of the University of California
25 *
26 * IDENTIFICATION
27 * src/backend/storage/lmgr/lwlock.c
28 *
29 * NOTES:
30 *
31 * This used to be a pretty straight forward reader-writer lock
32 * implementation, in which the internal state was protected by a
33 * spinlock. Unfortunately the overhead of taking the spinlock proved to be
34 * too high for workloads/locks that were taken in shared mode very
35 * frequently. Often we were spinning in the (obviously exclusive) spinlock,
36 * while trying to acquire a shared lock that was actually free.
37 *
38 * Thus a new implementation was devised that provides wait-free shared lock
39 * acquisition for locks that aren't exclusively locked.
40 *
41 * The basic idea is to have a single atomic variable 'lockcount' instead of
42 * the formerly separate shared and exclusive counters and to use atomic
43 * operations to acquire the lock. That's fairly easy to do for plain
44 * rw-spinlocks, but a lot harder for something like LWLocks that want to wait
45 * in the OS.
46 *
47 * For lock acquisition we use an atomic compare-and-exchange on the lockcount
48 * variable. For exclusive lock we swap in a sentinel value
49 * (LW_VAL_EXCLUSIVE), for shared locks we count the number of holders.
50 *
51 * To release the lock we use an atomic decrement to release the lock. If the
52 * new value is zero (we get that atomically), we know we can/have to release
53 * waiters.
54 *
55 * Obviously it is important that the sentinel value for exclusive locks
56 * doesn't conflict with the maximum number of possible share lockers -
57 * luckily MAX_BACKENDS makes that easily possible.
58 *
59 *
60 * The attentive reader might have noticed that naively doing the above has a
61 * glaring race condition: We try to lock using the atomic operations and
62 * notice that we have to wait. Unfortunately by the time we have finished
63 * queuing, the former locker very well might have already finished its
64 * work. That's problematic because we're now stuck waiting inside the OS.
65
66 * To mitigate those races we use a two phased attempt at locking:
67 * Phase 1: Try to do it atomically, if we succeed, nice
68 * Phase 2: Add ourselves to the waitqueue of the lock
69 * Phase 3: Try to grab the lock again, if we succeed, remove ourselves from
70 * the queue
71 * Phase 4: Sleep till wake-up, goto Phase 1
72 *
73 * This protects us against the problem from above as nobody can release too
74 * quick, before we're queued, since after Phase 2 we're already queued.
75 * -------------------------------------------------------------------------
76 */
77#include "postgres.h"
78
79#include "miscadmin.h"
80#include "pg_trace.h"
81#include "pgstat.h"
82#include "port/pg_bitutils.h"
83#include "storage/proc.h"
84#include "storage/proclist.h"
85#include "storage/procnumber.h"
86#include "storage/spin.h"
87#include "storage/subsystems.h"
88#include "utils/memutils.h"
89#include "utils/wait_event.h"
90
91#ifdef LWLOCK_STATS
92#include "utils/hsearch.h"
93#endif
94
95
96#define LW_FLAG_HAS_WAITERS ((uint32) 1 << 31)
97#define LW_FLAG_WAKE_IN_PROGRESS ((uint32) 1 << 30)
98#define LW_FLAG_LOCKED ((uint32) 1 << 29)
99#define LW_FLAG_BITS 3
100#define LW_FLAG_MASK (((1<<LW_FLAG_BITS)-1)<<(32-LW_FLAG_BITS))
101
102/* assumes MAX_BACKENDS is a (power of 2) - 1, checked below */
103#define LW_VAL_EXCLUSIVE (MAX_BACKENDS + 1)
104#define LW_VAL_SHARED 1
105
106/* already (power of 2)-1, i.e. suitable for a mask */
107#define LW_SHARED_MASK MAX_BACKENDS
108#define LW_LOCK_MASK (MAX_BACKENDS | LW_VAL_EXCLUSIVE)
109
110
112 "MAX_BACKENDS + 1 needs to be a power of 2");
113
115 "MAX_BACKENDS and LW_FLAG_MASK overlap");
116
118 "LW_VAL_EXCLUSIVE and LW_FLAG_MASK overlap");
119
120/*
121 * There are three sorts of LWLock "tranches":
122 *
123 * 1. The individually-named locks defined in lwlocklist.h each have their
124 * own tranche. We absorb the names of these tranches from there into
125 * BuiltinTrancheNames here.
126 *
127 * 2. There are some predefined tranches for built-in groups of locks defined
128 * in lwlocklist.h. We absorb the names of these tranches, too.
129 *
130 * 3. Extensions can create new tranches, via either RequestNamedLWLockTranche
131 * or LWLockNewTrancheId. These are stored in shared memory and can be
132 * accessed via LWLockTranches.
133 *
134 * All these names are user-visible as wait event names, so choose with care
135 * ... and do not forget to update the documentation's list of wait events.
136 */
137static const char *const BuiltinTrancheNames[] = {
138#define PG_LWLOCK(id, lockname) [id] = CppAsString(lockname),
139#define PG_LWLOCKTRANCHE(id, lockname) [LWTRANCHE_##id] = CppAsString(lockname),
140#include "storage/lwlocklist.h"
141#undef PG_LWLOCK
142#undef PG_LWLOCKTRANCHE
143};
144
147 "missing entries in BuiltinTrancheNames[]");
148
149/* Main array of LWLocks in shared memory */
151
152/*
153 * We use this structure to keep track of locked LWLocks for release
154 * during error recovery. Normally, only a few will be held at once, but
155 * occasionally the number can be much higher.
156 */
157#define MAX_SIMUL_LWLOCKS 200
158
159/* struct representing the LWLocks we're holding */
165
166static int num_held_lwlocks = 0;
168
169/* Maximum number of LWLock tranches that can be assigned by extensions */
170#define MAX_USER_DEFINED_TRANCHES 256
171
172/*
173 * Shared memory structure holding user-defined tranches.
174 */
176{
177 /* This is indexed by tranche ID minus LWTRANCHE_FIRST_USER_DEFINED */
178 struct
179 {
181
182 /*
183 * Index of the tranche's locks in MainLWLockArray if this tranche was
184 * allocated with RequestNamedLWLockTranche(), or -1 if the tranche
185 * was allocated with LWLockNewTrancheId()
186 */
189
190 int num_user_defined; /* 'user_defined' entries in use */
191
192 slock_t lock; /* protects the above */
194
196
197/* backend-local copy of LWLockTranches->num_user_defined */
199
200/*
201 * NamedLWLockTrancheRequests is a list of tranches requested with
202 * RequestNamedLWLockTranche(). It is only valid in the postmaster; after
203 * startup the tranches are tracked in LWLockTranches in shared memory.
204 */
210
212
213/* Size of MainLWLockArray. Only valid in postmaster. */
215
216static void LWLockShmemRequest(void *arg);
217static void LWLockShmemInit(void *arg);
218
223
224
225static inline void LWLockReportWaitStart(LWLock *lock);
226static inline void LWLockReportWaitEnd(void);
227static const char *GetLWTrancheName(uint16 trancheId);
228
229#define T_NAME(lock) \
230 GetLWTrancheName((lock)->tranche)
231
232#ifdef LWLOCK_STATS
233typedef struct lwlock_stats_key
234{
235 int tranche;
236 void *instance;
238
239typedef struct lwlock_stats
240{
244 int block_count;
248
249static HTAB *lwlock_stats_htab;
251#endif
252
253#ifdef LOCK_DEBUG
254bool Trace_lwlocks = false;
255
256inline static void
257PRINT_LWDEBUG(const char *where, LWLock *lock, LWLockMode mode)
258{
259 /* hide statement & context here, otherwise the log is just too verbose */
260 if (Trace_lwlocks)
261 {
263
264 ereport(LOG,
265 (errhidestmt(true),
266 errhidecontext(true),
267 errmsg_internal("%d: %s(%s %p): excl %u shared %u haswaiters %u waiters %u waking %d",
268 MyProcPid,
269 where, T_NAME(lock), lock,
270 (state & LW_VAL_EXCLUSIVE) != 0,
272 (state & LW_FLAG_HAS_WAITERS) != 0,
273 pg_atomic_read_u32(&lock->nwaiters),
275 }
276}
277
278inline static void
279LOG_LWDEBUG(const char *where, LWLock *lock, const char *msg)
280{
281 /* hide statement & context here, otherwise the log is just too verbose */
282 if (Trace_lwlocks)
283 {
284 ereport(LOG,
285 (errhidestmt(true),
286 errhidecontext(true),
287 errmsg_internal("%s(%s %p): %s", where,
288 T_NAME(lock), lock, msg)));
289 }
290}
291
292#else /* not LOCK_DEBUG */
293#define PRINT_LWDEBUG(a,b,c) ((void)0)
294#define LOG_LWDEBUG(a,b,c) ((void)0)
295#endif /* LOCK_DEBUG */
296
297#ifdef LWLOCK_STATS
298
299static void init_lwlock_stats(void);
300static void print_lwlock_stats(int code, Datum arg);
302
303static void
305{
306 HASHCTL ctl;
308 static bool exit_registered = false;
309
310 if (lwlock_stats_cxt != NULL)
312
313 /*
314 * The LWLock stats will be updated within a critical section, which
315 * requires allocating new hash entries. Allocations within a critical
316 * section are normally not allowed because running out of memory would
317 * lead to a PANIC, but LWLOCK_STATS is debugging code that's not normally
318 * turned on in production, so that's an acceptable risk. The hash entries
319 * are small, so the risk of running out of memory is minimal in practice.
320 */
322 "LWLock stats",
325
326 ctl.keysize = sizeof(lwlock_stats_key);
327 ctl.entrysize = sizeof(lwlock_stats);
328 ctl.hcxt = lwlock_stats_cxt;
329 lwlock_stats_htab = hash_create("lwlock stats", 16384, &ctl,
331 if (!exit_registered)
332 {
334 exit_registered = true;
335 }
336}
337
338static void
340{
341 HASH_SEQ_STATUS scan;
343
345
346 /* Grab an LWLock to keep different backends from mixing reports */
348
349 while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL)
350 {
352 "PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n",
353 MyProcPid, GetLWTrancheName(lwstats->key.tranche),
354 lwstats->key.instance, lwstats->sh_acquire_count,
355 lwstats->ex_acquire_count, lwstats->block_count,
356 lwstats->spin_delay_count, lwstats->dequeue_self_count);
357 }
358
360}
361
362static lwlock_stats *
364{
367 bool found;
368
369 /*
370 * During shared memory initialization, the hash table doesn't exist yet.
371 * Stats of that phase aren't very interesting, so just collect operations
372 * on all locks in a single dummy entry.
373 */
374 if (lwlock_stats_htab == NULL)
375 return &lwlock_stats_dummy;
376
377 /* Fetch or create the entry. */
378 MemSet(&key, 0, sizeof(key));
379 key.tranche = lock->tranche;
380 key.instance = lock;
382 if (!found)
383 {
384 lwstats->sh_acquire_count = 0;
385 lwstats->ex_acquire_count = 0;
386 lwstats->block_count = 0;
387 lwstats->dequeue_self_count = 0;
388 lwstats->spin_delay_count = 0;
389 }
390 return lwstats;
391}
392#endif /* LWLOCK_STATS */
393
394
395/*
396 * Compute number of LWLocks required by user-defined tranches requested with
397 * RequestNamedLWLockTranche(). These will be allocated in the main array.
398 */
399static int
401{
402 int numLocks = 0;
403
405 {
406 numLocks += request->num_lwlocks;
407 }
408
409 return numLocks;
410}
411
412/*
413 * Request shmem space for user-defined tranches and the main LWLock array.
414 */
415static void
417{
418 size_t size;
419
420 /* Space for user-defined tranches */
421 ShmemRequestStruct(.name = "LWLock tranches",
422 .size = sizeof(LWLockTrancheShmemData),
423 .ptr = (void **) &LWLockTranches,
424 );
425
426 /* Space for the LWLock array */
428 {
430 size = num_main_array_locks * sizeof(LWLockPadded);
431 }
432 else
434
435 ShmemRequestStruct(.name = "Main LWLock array",
436 .size = size,
437 .ptr = (void **) &MainLWLockArray,
438 );
439}
440
441/*
442 * Initialize shmem space for user-defined tranches and the main LWLock array.
443 */
444static void
446{
447 int pos;
448
449 /* Initialize the dynamic-allocation counter for tranches */
451
453
454 /*
455 * Allocate and initialize all LWLocks in the main array. It includes all
456 * LWLocks for built-in tranches and those requested with
457 * RequestNamedLWLockTranche().
458 */
459 pos = 0;
460
461 /* Initialize all individual LWLocks in main array */
462 for (int id = 0; id < NUM_INDIVIDUAL_LWLOCKS; id++)
463 LWLockInitialize(&MainLWLockArray[pos++].lock, id);
464
465 /* Initialize buffer mapping LWLocks in main array */
467 for (int i = 0; i < NUM_BUFFER_PARTITIONS; i++)
469
470 /* Initialize lmgrs' LWLocks in main array */
472 for (int i = 0; i < NUM_LOCK_PARTITIONS; i++)
474
475 /* Initialize predicate lmgrs' LWLocks in main array */
477 for (int i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++)
479
480 /*
481 * Copy the info about any user-defined tranches into shared memory (so
482 * that other processes can see it), and initialize the requested LWLocks.
483 */
486 {
488
490 request->tranche_name,
493
494 for (int i = 0; i < request->num_lwlocks; i++)
496 }
497
498 /* Cross-check that we agree on the total size with LWLockShmemRequest() */
500}
501
502/*
503 * InitLWLockAccess - initialize backend-local state needed to hold LWLocks
504 */
505void
507{
508#ifdef LWLOCK_STATS
510#endif
511}
512
513/*
514 * GetNamedLWLockTranche - returns the base address of LWLock from the
515 * specified tranche.
516 *
517 * Caller needs to retrieve the requested number of LWLocks starting from
518 * the base lock address returned by this API. This can be used for
519 * tranches that are requested by using RequestNamedLWLockTranche() API.
520 */
522GetNamedLWLockTranche(const char *tranche_name)
523{
527
528 /*
529 * Obtain the position of base address of LWLock belonging to requested
530 * tranche_name in MainLWLockArray. LWLocks for user-defined tranches
531 * requested with RequestNamedLWLockTranche() are placed in
532 * MainLWLockArray after fixed locks.
533 */
534 for (int i = 0; i < LocalNumUserDefinedTranches; i++)
535 {
537 tranche_name) == 0)
538 {
540
541 /*
542 * GetNamedLWLockTranche() should only be used for locks requested
543 * with RequestNamedLWLockTranche(), not those allocated with
544 * LWLockNewTrancheId().
545 */
546 if (lock_pos == -1)
547 elog(ERROR, "requested tranche was not registered with RequestNamedLWLockTranche()");
548 return &MainLWLockArray[lock_pos];
549 }
550 }
551
552 elog(ERROR, "requested tranche is not registered");
553
554 /* just to keep compiler quiet */
555 return NULL;
556}
557
558/*
559 * Allocate a new tranche ID with the provided name.
560 */
561int
563{
564 int idx;
565
566 if (!name)
569 errmsg("tranche name cannot be NULL")));
570
571 if (strlen(name) >= NAMEDATALEN)
574 errmsg("tranche name too long"),
575 errdetail("LWLock tranche names must be no longer than %d bytes.",
576 NAMEDATALEN - 1)));
577
578 /* The counter and the tranche names are protected by the spinlock */
580
582 {
585 (errmsg("maximum number of tranches already registered"),
586 errdetail("No more than %d tranches may be registered.",
588 }
589
590 /* Allocate an entry in the user_defined array */
592
593 /* update our local copy while we're at it */
595
596 /* Initialize it */
598
599 /* the locks are not in the main array */
601
603
605}
606
607/*
608 * RequestNamedLWLockTranche
609 * Request that extra LWLocks be allocated during postmaster
610 * startup.
611 *
612 * This may only be called via the shmem_request_hook of a library that is
613 * loaded into the postmaster via shared_preload_libraries. Calls from
614 * elsewhere will fail.
615 *
616 * The tranche name will be user-visible as a wait event name, so try to
617 * use a name that fits the style for those.
618 */
619void
620RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
621{
623 MemoryContext oldcontext;
624
626 elog(FATAL, "cannot request additional LWLocks outside shmem_request_hook");
627
628 if (!tranche_name)
631 errmsg("tranche name cannot be NULL")));
632
633 if (strlen(tranche_name) >= NAMEDATALEN)
636 errmsg("tranche name too long"),
637 errdetail("LWLock tranche names must be no longer than %d bytes.",
638 NAMEDATALEN - 1)));
639
642 (errmsg("maximum number of tranches already registered"),
643 errdetail("No more than %d tranches may be registered.",
645
646 /* Check that the name isn't already in use */
648 {
649 if (strcmp(existing->tranche_name, tranche_name) == 0)
650 elog(ERROR, "requested tranche \"%s\" is already registered", tranche_name);
651 }
652
655 else
657
659 strlcpy(request->tranche_name, tranche_name, NAMEDATALEN);
660 request->num_lwlocks = num_lwlocks;
662
663 MemoryContextSwitchTo(oldcontext);
664}
665
666/*
667 * LWLockInitialize - initialize a new lwlock; it's initially unlocked
668 */
669void
670LWLockInitialize(LWLock *lock, int tranche_id)
671{
672 /* verify the tranche_id is valid */
673 (void) GetLWTrancheName(tranche_id);
674
675 pg_atomic_init_u32(&lock->state, 0);
676#ifdef LOCK_DEBUG
677 pg_atomic_init_u32(&lock->nwaiters, 0);
678#endif
679 lock->tranche = tranche_id;
680 proclist_init(&lock->waiters);
681}
682
683/*
684 * Report start of wait event for light-weight locks.
685 *
686 * This function will be used by all the light-weight lock calls which
687 * needs to wait to acquire the lock. This function distinguishes wait
688 * event based on tranche and lock id.
689 */
690static inline void
695
696/*
697 * Report end of wait event for light-weight locks.
698 */
699static inline void
704
705/*
706 * Return the name of an LWLock tranche.
707 */
708static const char *
710{
711 int idx;
712
713 /* Built-in tranche or individual LWLock? */
716
717 /*
718 * It's an extension tranche, so look in LWLockTranches->user_defined.
719 */
721
722 /*
723 * We only ever add new entries to LWLockTranches->user_defined, so most
724 * lookups can avoid taking the spinlock as long as the backend-local
725 * counter (LocalNumUserDefinedTranches) is greater than the requested
726 * tranche ID. Else, we need to first update the backend-local counter
727 * with the spinlock held before attempting the lookup again. In
728 * practice, the latter case is probably rare.
729 */
731 {
735
737 elog(ERROR, "tranche %d is not registered", trancheId);
738 }
739
741}
742
743/*
744 * Return an identifier for an LWLock based on the wait class and event.
745 */
746const char *
748{
749 Assert(classId == PG_WAIT_LWLOCK);
750 /* The event IDs are just tranche numbers. */
752}
753
754/*
755 * Internal function that tries to atomically acquire the lwlock in the passed
756 * in mode.
757 *
758 * This function will not block waiting for a lock to become free - that's the
759 * caller's job.
760 *
761 * Returns true if the lock isn't free and we need to wait.
762 */
763static bool
765{
767
769
770 /*
771 * Read once outside the loop, later iterations will get the newer value
772 * via compare & exchange.
773 */
775
776 /* loop until we've determined whether we could acquire the lock or not */
777 while (true)
778 {
780 bool lock_free;
781
783
784 if (mode == LW_EXCLUSIVE)
785 {
787 if (lock_free)
789 }
790 else
791 {
793 if (lock_free)
795 }
796
797 /*
798 * Attempt to swap in the state we are expecting. If we didn't see
799 * lock to be free, that's just the old value. If we saw it as free,
800 * we'll attempt to mark it acquired. The reason that we always swap
801 * in the value is that this doubles as a memory barrier. We could try
802 * to be smarter and only swap in values if we saw the lock as free,
803 * but benchmark haven't shown it as beneficial so far.
804 *
805 * Retry if the value changed since we last looked at it.
806 */
809 {
810 if (lock_free)
811 {
812 /* Great! Got the lock. */
813#ifdef LOCK_DEBUG
814 if (mode == LW_EXCLUSIVE)
815 lock->owner = MyProc;
816#endif
817 return false;
818 }
819 else
820 return true; /* somebody else has the lock */
821 }
822 }
824}
825
826/*
827 * Lock the LWLock's wait list against concurrent activity.
828 *
829 * NB: even though the wait list is locked, non-conflicting lock operations
830 * may still happen concurrently.
831 *
832 * Time spent holding mutex should be short!
833 */
834static void
836{
838#ifdef LWLOCK_STATS
840 uint32 delays = 0;
841
843#endif
844
845 while (true)
846 {
847 /*
848 * Always try once to acquire the lock directly, without setting up
849 * the spin-delay infrastructure. The work necessary for that shows up
850 * in profiles and is rarely necessary.
851 */
854 break; /* got lock */
855
856 /* and then spin without atomic operations until lock is released */
857 {
859
861
862 while (old_state & LW_FLAG_LOCKED)
863 {
866 }
867#ifdef LWLOCK_STATS
868 delays += delayStatus.delays;
869#endif
871 }
872
873 /*
874 * Retry. The lock might obviously already be re-acquired by the time
875 * we're attempting to get it again.
876 */
877 }
878
879#ifdef LWLOCK_STATS
880 lwstats->spin_delay_count += delays;
881#endif
882}
883
884/*
885 * Unlock the LWLock's wait list.
886 *
887 * Note that it can be more efficient to manipulate flags and release the
888 * locks in a single atomic operation.
889 */
890static void
899
900/*
901 * Wakeup all the lockers that currently have a chance to acquire the lock.
902 */
903static void
905{
906 bool new_wake_in_progress = false;
907 bool wokeup_somebody = false;
910
912
913 /* lock wait list while collecting backends to wake up */
914 LWLockWaitListLock(lock);
915
916 proclist_foreach_modify(iter, &lock->waiters, lwWaitLink)
917 {
918 PGPROC *waiter = GetPGProcByNumber(iter.cur);
919
920 if (wokeup_somebody && waiter->lwWaitMode == LW_EXCLUSIVE)
921 continue;
922
923 proclist_delete(&lock->waiters, iter.cur, lwWaitLink);
924 proclist_push_tail(&wakeup, iter.cur, lwWaitLink);
925
926 if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE)
927 {
928 /*
929 * Prevent additional wakeups until retryer gets to run. Backends
930 * that are just waiting for the lock to become free don't retry
931 * automatically.
932 */
934
935 /*
936 * Don't wakeup (further) exclusive locks.
937 */
938 wokeup_somebody = true;
939 }
940
941 /*
942 * Signal that the process isn't on the wait list anymore. This allows
943 * LWLockDequeueSelf() to remove itself of the waitlist with a
944 * proclist_delete(), rather than having to check if it has been
945 * removed from the list.
946 */
947 Assert(waiter->lwWaiting == LW_WS_WAITING);
949
950 /*
951 * Once we've woken up an exclusive lock, there's no point in waking
952 * up anybody else.
953 */
954 if (waiter->lwWaitMode == LW_EXCLUSIVE)
955 break;
956 }
957
959
960 /* unset required flags, and release lock, in one fell swoop */
961 {
964
966 while (true)
967 {
969
970 /* compute desired flags */
971
974 else
976
977 if (proclist_is_empty(&lock->waiters))
979
980 desired_state &= ~LW_FLAG_LOCKED; /* release lock */
981
984 break;
985 }
986 }
987
988 /* Awaken any waiters I removed from the queue. */
989 proclist_foreach_modify(iter, &wakeup, lwWaitLink)
990 {
991 PGPROC *waiter = GetPGProcByNumber(iter.cur);
992
993 LOG_LWDEBUG("LWLockRelease", lock, "release waiter");
994 proclist_delete(&wakeup, iter.cur, lwWaitLink);
995
996 /*
997 * Guarantee that lwWaiting being unset only becomes visible once the
998 * unlink from the link has completed. Otherwise the target backend
999 * could be woken up for other reason and enqueue for a new lock - if
1000 * that happens before the list unlink happens, the list would end up
1001 * being corrupted.
1002 *
1003 * The barrier pairs with the LWLockWaitListLock() when enqueuing for
1004 * another lock.
1005 */
1007 waiter->lwWaiting = LW_WS_NOT_WAITING;
1008 PGSemaphoreUnlock(waiter->sem);
1009 }
1010}
1011
1012/*
1013 * Add ourselves to the end of the queue.
1014 *
1015 * NB: Mode can be LW_WAIT_UNTIL_FREE here!
1016 */
1017static void
1019{
1020 /*
1021 * If we don't have a PGPROC structure, there's no way to wait. This
1022 * should never occur, since MyProc should only be null during shared
1023 * memory initialization.
1024 */
1025 if (MyProc == NULL)
1026 elog(PANIC, "cannot wait without a PGPROC structure");
1027
1029 elog(PANIC, "queueing for lock while waiting on another one");
1030
1031 LWLockWaitListLock(lock);
1032
1033 /* setting the flag is protected by the spinlock */
1035
1038
1039 /* LW_WAIT_UNTIL_FREE waiters are always at the front of the queue */
1040 if (mode == LW_WAIT_UNTIL_FREE)
1041 proclist_push_head(&lock->waiters, MyProcNumber, lwWaitLink);
1042 else
1043 proclist_push_tail(&lock->waiters, MyProcNumber, lwWaitLink);
1044
1045 /* Can release the mutex now */
1047
1048#ifdef LOCK_DEBUG
1049 pg_atomic_fetch_add_u32(&lock->nwaiters, 1);
1050#endif
1051}
1052
1053/*
1054 * Remove ourselves from the waitlist.
1055 *
1056 * This is used if we queued ourselves because we thought we needed to sleep
1057 * but, after further checking, we discovered that we don't actually need to
1058 * do so.
1059 */
1060static void
1062{
1063 bool on_waitlist;
1064
1065#ifdef LWLOCK_STATS
1067
1069
1070 lwstats->dequeue_self_count++;
1071#endif
1072
1073 LWLockWaitListLock(lock);
1074
1075 /*
1076 * Remove ourselves from the waitlist, unless we've already been removed.
1077 * The removal happens with the wait list lock held, so there's no race in
1078 * this check.
1079 */
1081 if (on_waitlist)
1082 proclist_delete(&lock->waiters, MyProcNumber, lwWaitLink);
1083
1084 if (proclist_is_empty(&lock->waiters) &&
1086 {
1088 }
1089
1090 /* XXX: combine with fetch_and above? */
1092
1093 /* clear waiting state again, nice for debugging */
1094 if (on_waitlist)
1096 else
1097 {
1098 int extraWaits = 0;
1099
1100 /*
1101 * Somebody else dequeued us and has or will wake us up. Deal with the
1102 * superfluous absorption of a wakeup.
1103 */
1104
1105 /*
1106 * Clear LW_FLAG_WAKE_IN_PROGRESS if somebody woke us before we
1107 * removed ourselves - they'll have set it.
1108 */
1110
1111 /*
1112 * Now wait for the scheduled wakeup, otherwise our ->lwWaiting would
1113 * get reset at some inconvenient point later. Most of the time this
1114 * will immediately return.
1115 */
1116 for (;;)
1117 {
1120 break;
1121 extraWaits++;
1122 }
1123
1124 /*
1125 * Fix the process wait semaphore's count for any absorbed wakeups.
1126 */
1127 while (extraWaits-- > 0)
1129 }
1130
1131#ifdef LOCK_DEBUG
1132 {
1133 /* not waiting anymore */
1135
1137 }
1138#endif
1139}
1140
1141/*
1142 * LWLockAcquire - acquire a lightweight lock in the specified mode
1143 *
1144 * If the lock is not available, sleep until it is. Returns true if the lock
1145 * was available immediately, false if we had to sleep.
1146 *
1147 * Side effect: cancel/die interrupts are held off until lock release.
1148 */
1149bool
1151{
1152 PGPROC *proc = MyProc;
1153 bool result = true;
1154 int extraWaits = 0;
1155#ifdef LWLOCK_STATS
1157
1159#endif
1160
1162
1163 PRINT_LWDEBUG("LWLockAcquire", lock, mode);
1164
1165#ifdef LWLOCK_STATS
1166 /* Count lock acquisition attempts */
1167 if (mode == LW_EXCLUSIVE)
1168 lwstats->ex_acquire_count++;
1169 else
1170 lwstats->sh_acquire_count++;
1171#endif /* LWLOCK_STATS */
1172
1173 /*
1174 * We can't wait if we haven't got a PGPROC. This should only occur
1175 * during bootstrap or shared memory initialization. Put an Assert here
1176 * to catch unsafe coding practices.
1177 */
1178 Assert(!(proc == NULL && IsUnderPostmaster));
1179
1180 /* Ensure we will have room to remember the lock */
1182 elog(ERROR, "too many LWLocks taken");
1183
1184 /*
1185 * Lock out cancel/die interrupts until we exit the code section protected
1186 * by the LWLock. This ensures that interrupts will not interfere with
1187 * manipulations of data structures in shared memory.
1188 */
1190
1191 /*
1192 * Loop here to try to acquire lock after each time we are signaled by
1193 * LWLockRelease.
1194 *
1195 * NOTE: it might seem better to have LWLockRelease actually grant us the
1196 * lock, rather than retrying and possibly having to go back to sleep. But
1197 * in practice that is no good because it means a process swap for every
1198 * lock acquisition when two or more processes are contending for the same
1199 * lock. Since LWLocks are normally used to protect not-very-long
1200 * sections of computation, a process needs to be able to acquire and
1201 * release the same lock many times during a single CPU time slice, even
1202 * in the presence of contention. The efficiency of being able to do that
1203 * outweighs the inefficiency of sometimes wasting a process dispatch
1204 * cycle because the lock is not free when a released waiter finally gets
1205 * to run. See pgsql-hackers archives for 29-Dec-01.
1206 */
1207 for (;;)
1208 {
1209 bool mustwait;
1210
1211 /*
1212 * Try to grab the lock the first time, we're not in the waitqueue
1213 * yet/anymore.
1214 */
1216
1217 if (!mustwait)
1218 {
1219 LOG_LWDEBUG("LWLockAcquire", lock, "immediately acquired lock");
1220 break; /* got the lock */
1221 }
1222
1223 /*
1224 * Ok, at this point we couldn't grab the lock on the first try. We
1225 * cannot simply queue ourselves to the end of the list and wait to be
1226 * woken up because by now the lock could long have been released.
1227 * Instead add us to the queue and try to grab the lock again. If we
1228 * succeed we need to revert the queuing and be happy, otherwise we
1229 * recheck the lock. If we still couldn't grab it, we know that the
1230 * other locker will see our queue entries when releasing since they
1231 * existed before we checked for the lock.
1232 */
1233
1234 /* add to the queue */
1235 LWLockQueueSelf(lock, mode);
1236
1237 /* we're now guaranteed to be woken up if necessary */
1239
1240 /* ok, grabbed the lock the second time round, need to undo queueing */
1241 if (!mustwait)
1242 {
1243 LOG_LWDEBUG("LWLockAcquire", lock, "acquired, undoing queue");
1244
1245 LWLockDequeueSelf(lock);
1246 break;
1247 }
1248
1249 /*
1250 * Wait until awakened.
1251 *
1252 * It is possible that we get awakened for a reason other than being
1253 * signaled by LWLockRelease. If so, loop back and wait again. Once
1254 * we've gotten the LWLock, re-increment the sema by the number of
1255 * additional signals received.
1256 */
1257 LOG_LWDEBUG("LWLockAcquire", lock, "waiting");
1258
1259#ifdef LWLOCK_STATS
1260 lwstats->block_count++;
1261#endif
1262
1266
1267 for (;;)
1268 {
1269 PGSemaphoreLock(proc->sem);
1270 if (proc->lwWaiting == LW_WS_NOT_WAITING)
1271 break;
1272 extraWaits++;
1273 }
1274
1275 /* Retrying, allow LWLockRelease to release waiters again. */
1277
1278#ifdef LOCK_DEBUG
1279 {
1280 /* not waiting anymore */
1282
1284 }
1285#endif
1286
1290
1291 LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
1292
1293 /* Now loop back and try to acquire lock again. */
1294 result = false;
1295 }
1296
1299
1300 /* Add lock to list of locks held by this backend */
1303
1304 /*
1305 * Fix the process wait semaphore's count for any absorbed wakeups.
1306 */
1307 while (extraWaits-- > 0)
1308 PGSemaphoreUnlock(proc->sem);
1309
1310 return result;
1311}
1312
1313/*
1314 * LWLockConditionalAcquire - acquire a lightweight lock in the specified mode
1315 *
1316 * If the lock is not available, return false with no side-effects.
1317 *
1318 * If successful, cancel/die interrupts are held off until lock release.
1319 */
1320bool
1322{
1323 bool mustwait;
1324
1326
1327 PRINT_LWDEBUG("LWLockConditionalAcquire", lock, mode);
1328
1329 /* Ensure we will have room to remember the lock */
1331 elog(ERROR, "too many LWLocks taken");
1332
1333 /*
1334 * Lock out cancel/die interrupts until we exit the code section protected
1335 * by the LWLock. This ensures that interrupts will not interfere with
1336 * manipulations of data structures in shared memory.
1337 */
1339
1340 /* Check for the lock */
1342
1343 if (mustwait)
1344 {
1345 /* Failed to get lock, so release interrupt holdoff */
1347
1348 LOG_LWDEBUG("LWLockConditionalAcquire", lock, "failed");
1351 }
1352 else
1353 {
1354 /* Add lock to list of locks held by this backend */
1359 }
1360 return !mustwait;
1361}
1362
1363/*
1364 * LWLockAcquireOrWait - Acquire lock, or wait until it's free
1365 *
1366 * The semantics of this function are a bit funky. If the lock is currently
1367 * free, it is acquired in the given mode, and the function returns true. If
1368 * the lock isn't immediately free, the function waits until it is released
1369 * and returns false, but does not acquire the lock.
1370 *
1371 * This is currently used for WALWriteLock: when a backend flushes the WAL,
1372 * holding WALWriteLock, it can flush the commit records of many other
1373 * backends as a side-effect. Those other backends need to wait until the
1374 * flush finishes, but don't need to acquire the lock anymore. They can just
1375 * wake up, observe that their records have already been flushed, and return.
1376 */
1377bool
1379{
1380 PGPROC *proc = MyProc;
1381 bool mustwait;
1382 int extraWaits = 0;
1383#ifdef LWLOCK_STATS
1385
1387#endif
1388
1390
1391 PRINT_LWDEBUG("LWLockAcquireOrWait", lock, mode);
1392
1393 /* Ensure we will have room to remember the lock */
1395 elog(ERROR, "too many LWLocks taken");
1396
1397 /*
1398 * Lock out cancel/die interrupts until we exit the code section protected
1399 * by the LWLock. This ensures that interrupts will not interfere with
1400 * manipulations of data structures in shared memory.
1401 */
1403
1404 /*
1405 * NB: We're using nearly the same twice-in-a-row lock acquisition
1406 * protocol as LWLockAcquire(). Check its comments for details.
1407 */
1409
1410 if (mustwait)
1411 {
1413
1415
1416 if (mustwait)
1417 {
1418 /*
1419 * Wait until awakened. Like in LWLockAcquire, be prepared for
1420 * bogus wakeups.
1421 */
1422 LOG_LWDEBUG("LWLockAcquireOrWait", lock, "waiting");
1423
1424#ifdef LWLOCK_STATS
1425 lwstats->block_count++;
1426#endif
1427
1431
1432 for (;;)
1433 {
1434 PGSemaphoreLock(proc->sem);
1435 if (proc->lwWaiting == LW_WS_NOT_WAITING)
1436 break;
1437 extraWaits++;
1438 }
1439
1440#ifdef LOCK_DEBUG
1441 {
1442 /* not waiting anymore */
1444
1446 }
1447#endif
1451
1452 LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened");
1453 }
1454 else
1455 {
1456 LOG_LWDEBUG("LWLockAcquireOrWait", lock, "acquired, undoing queue");
1457
1458 /*
1459 * Got lock in the second attempt, undo queueing. We need to treat
1460 * this as having successfully acquired the lock, otherwise we'd
1461 * not necessarily wake up people we've prevented from acquiring
1462 * the lock.
1463 */
1464 LWLockDequeueSelf(lock);
1465 }
1466 }
1467
1468 /*
1469 * Fix the process wait semaphore's count for any absorbed wakeups.
1470 */
1471 while (extraWaits-- > 0)
1472 PGSemaphoreUnlock(proc->sem);
1473
1474 if (mustwait)
1475 {
1476 /* Failed to get lock, so release interrupt holdoff */
1478 LOG_LWDEBUG("LWLockAcquireOrWait", lock, "failed");
1481 }
1482 else
1483 {
1484 LOG_LWDEBUG("LWLockAcquireOrWait", lock, "succeeded");
1485 /* Add lock to list of locks held by this backend */
1490 }
1491
1492 return !mustwait;
1493}
1494
1495/*
1496 * Does the lwlock in its current state need to wait for the variable value to
1497 * change?
1498 *
1499 * If we don't need to wait, and it's because the value of the variable has
1500 * changed, store the current value in newval.
1501 *
1502 * *result is set to true if the lock was free, and false otherwise.
1503 */
1504static bool
1506 uint64 *newval, bool *result)
1507{
1508 bool mustwait;
1509 uint64 value;
1510
1511 /*
1512 * Test first to see if it the slot is free right now.
1513 *
1514 * XXX: the unique caller of this routine, WaitXLogInsertionsToFinish()
1515 * via LWLockWaitForVar(), uses an implied barrier with a spinlock before
1516 * this, so we don't need a memory barrier here as far as the current
1517 * usage is concerned. But that might not be safe in general.
1518 */
1520
1521 if (!mustwait)
1522 {
1523 *result = true;
1524 return false;
1525 }
1526
1527 *result = false;
1528
1529 /*
1530 * Reading this value atomically is safe even on platforms where uint64
1531 * cannot be read without observing a torn value.
1532 */
1534
1535 if (value != oldval)
1536 {
1537 mustwait = false;
1538 *newval = value;
1539 }
1540 else
1541 {
1542 mustwait = true;
1543 }
1544
1545 return mustwait;
1546}
1547
1548/*
1549 * LWLockWaitForVar - Wait until lock is free, or a variable is updated.
1550 *
1551 * If the lock is held and *valptr equals oldval, waits until the lock is
1552 * either freed, or the lock holder updates *valptr by calling
1553 * LWLockUpdateVar. If the lock is free on exit (immediately or after
1554 * waiting), returns true. If the lock is still held, but *valptr no longer
1555 * matches oldval, returns false and sets *newval to the current value in
1556 * *valptr.
1557 *
1558 * Note: this function ignores shared lock holders; if the lock is held
1559 * in shared mode, returns 'true'.
1560 *
1561 * Be aware that LWLockConflictsWithVar() does not include a memory barrier,
1562 * hence the caller of this function may want to rely on an explicit barrier or
1563 * an implied barrier via spinlock or LWLock to avoid memory ordering issues.
1564 */
1565bool
1567 uint64 *newval)
1568{
1569 PGPROC *proc = MyProc;
1570 int extraWaits = 0;
1571 bool result = false;
1572#ifdef LWLOCK_STATS
1574
1576#endif
1577
1578 PRINT_LWDEBUG("LWLockWaitForVar", lock, LW_WAIT_UNTIL_FREE);
1579
1580 /*
1581 * Lock out cancel/die interrupts while we sleep on the lock. There is no
1582 * cleanup mechanism to remove us from the wait queue if we got
1583 * interrupted.
1584 */
1586
1587 /*
1588 * Loop here to check the lock's status after each time we are signaled.
1589 */
1590 for (;;)
1591 {
1592 bool mustwait;
1593
1595 &result);
1596
1597 if (!mustwait)
1598 break; /* the lock was free or value didn't match */
1599
1600 /*
1601 * Add myself to wait queue. Note that this is racy, somebody else
1602 * could wakeup before we're finished queuing. NB: We're using nearly
1603 * the same twice-in-a-row lock acquisition protocol as
1604 * LWLockAcquire(). Check its comments for details. The only
1605 * difference is that we also have to check the variable's values when
1606 * checking the state of the lock.
1607 */
1609
1610 /*
1611 * Clear LW_FLAG_WAKE_IN_PROGRESS flag, to make sure we get woken up
1612 * as soon as the lock is released.
1613 */
1615
1616 /*
1617 * We're now guaranteed to be woken up if necessary. Recheck the lock
1618 * and variables state.
1619 */
1621 &result);
1622
1623 /* Ok, no conflict after we queued ourselves. Undo queueing. */
1624 if (!mustwait)
1625 {
1626 LOG_LWDEBUG("LWLockWaitForVar", lock, "free, undoing queue");
1627
1628 LWLockDequeueSelf(lock);
1629 break;
1630 }
1631
1632 /*
1633 * Wait until awakened.
1634 *
1635 * It is possible that we get awakened for a reason other than being
1636 * signaled by LWLockRelease. If so, loop back and wait again. Once
1637 * we've gotten the LWLock, re-increment the sema by the number of
1638 * additional signals received.
1639 */
1640 LOG_LWDEBUG("LWLockWaitForVar", lock, "waiting");
1641
1642#ifdef LWLOCK_STATS
1643 lwstats->block_count++;
1644#endif
1645
1649
1650 for (;;)
1651 {
1652 PGSemaphoreLock(proc->sem);
1653 if (proc->lwWaiting == LW_WS_NOT_WAITING)
1654 break;
1655 extraWaits++;
1656 }
1657
1658#ifdef LOCK_DEBUG
1659 {
1660 /* not waiting anymore */
1662
1664 }
1665#endif
1666
1670
1671 LOG_LWDEBUG("LWLockWaitForVar", lock, "awakened");
1672
1673 /* Now loop back and check the status of the lock again. */
1674 }
1675
1676 /*
1677 * Fix the process wait semaphore's count for any absorbed wakeups.
1678 */
1679 while (extraWaits-- > 0)
1680 PGSemaphoreUnlock(proc->sem);
1681
1682 /*
1683 * Now okay to allow cancel/die interrupts.
1684 */
1686
1687 return result;
1688}
1689
1690
1691/*
1692 * LWLockUpdateVar - Update a variable and wake up waiters atomically
1693 *
1694 * Sets *valptr to 'val', and wakes up all processes waiting for us with
1695 * LWLockWaitForVar(). It first sets the value atomically and then wakes up
1696 * waiting processes so that any process calling LWLockWaitForVar() on the same
1697 * lock is guaranteed to see the new value, and act accordingly.
1698 *
1699 * The caller must be holding the lock in exclusive mode.
1700 */
1701void
1703{
1706
1707 PRINT_LWDEBUG("LWLockUpdateVar", lock, LW_EXCLUSIVE);
1708
1709 /*
1710 * Note that pg_atomic_exchange_u64 is a full barrier, so we're guaranteed
1711 * that the variable is updated before waking up waiters.
1712 */
1714
1716
1717 LWLockWaitListLock(lock);
1718
1720
1721 /*
1722 * See if there are any LW_WAIT_UNTIL_FREE waiters that need to be woken
1723 * up. They are always in the front of the queue.
1724 */
1725 proclist_foreach_modify(iter, &lock->waiters, lwWaitLink)
1726 {
1727 PGPROC *waiter = GetPGProcByNumber(iter.cur);
1728
1729 if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE)
1730 break;
1731
1732 proclist_delete(&lock->waiters, iter.cur, lwWaitLink);
1733 proclist_push_tail(&wakeup, iter.cur, lwWaitLink);
1734
1735 /* see LWLockWakeup() */
1736 Assert(waiter->lwWaiting == LW_WS_WAITING);
1738 }
1739
1740 /* We are done updating shared state of the lock itself. */
1742
1743 /*
1744 * Awaken any waiters I removed from the queue.
1745 */
1746 proclist_foreach_modify(iter, &wakeup, lwWaitLink)
1747 {
1748 PGPROC *waiter = GetPGProcByNumber(iter.cur);
1749
1750 proclist_delete(&wakeup, iter.cur, lwWaitLink);
1751 /* check comment in LWLockWakeup() about this barrier */
1753 waiter->lwWaiting = LW_WS_NOT_WAITING;
1754 PGSemaphoreUnlock(waiter->sem);
1755 }
1756}
1757
1758
1759/*
1760 * LWLockRelease - release a previously acquired lock
1761 *
1762 * NB: This will leave lock->owner pointing to the current backend (if
1763 * LOCK_DEBUG is set). This is somewhat intentional, as it makes it easier to
1764 * debug cases of missing wakeups during lock release.
1765 */
1766void
1768{
1771 bool check_waiters;
1772 int i;
1773
1774 /*
1775 * Remove lock from list of locks held. Usually, but not always, it will
1776 * be the latest-acquired lock; so search array backwards.
1777 */
1778 for (i = num_held_lwlocks; --i >= 0;)
1779 if (lock == held_lwlocks[i].lock)
1780 break;
1781
1782 if (i < 0)
1783 elog(ERROR, "lock %s is not held", T_NAME(lock));
1784
1786
1788 for (; i < num_held_lwlocks; i++)
1789 held_lwlocks[i] = held_lwlocks[i + 1];
1790
1791 PRINT_LWDEBUG("LWLockRelease", lock, mode);
1792
1793 /*
1794 * Release my hold on lock, after that it can immediately be acquired by
1795 * others, even if we still have to wakeup other waiters.
1796 */
1797 if (mode == LW_EXCLUSIVE)
1799 else
1801
1802 /* nobody else can have that kind of lock */
1804
1807
1808 /*
1809 * Check if we're still waiting for backends to get scheduled, if so,
1810 * don't wake them up again.
1811 */
1812 if ((oldstate & LW_FLAG_HAS_WAITERS) &&
1814 (oldstate & LW_LOCK_MASK) == 0)
1815 check_waiters = true;
1816 else
1817 check_waiters = false;
1818
1819 /*
1820 * As waking up waiters requires the spinlock to be acquired, only do so
1821 * if necessary.
1822 */
1823 if (check_waiters)
1824 {
1825 /* XXX: remove before commit? */
1826 LOG_LWDEBUG("LWLockRelease", lock, "releasing waiters");
1827 LWLockWakeup(lock);
1828 }
1829
1830 /*
1831 * Now okay to allow cancel/die interrupts.
1832 */
1834}
1835
1836/*
1837 * LWLockReleaseClearVar - release a previously acquired lock, reset variable
1838 */
1839void
1841{
1842 /*
1843 * Note that pg_atomic_exchange_u64 is a full barrier, so we're guaranteed
1844 * that the variable is updated before releasing the lock.
1845 */
1847
1848 LWLockRelease(lock);
1849}
1850
1851
1852/*
1853 * LWLockReleaseAll - release all currently-held locks
1854 *
1855 * Used to clean up after ereport(ERROR). An important difference between this
1856 * function and retail LWLockRelease calls is that InterruptHoldoffCount is
1857 * unchanged by this operation. This is necessary since InterruptHoldoffCount
1858 * has been set to an appropriate level earlier in error recovery. We could
1859 * decrement it below zero if we allow it to drop for each released lock!
1860 *
1861 * Note that this function must be safe to call even before the LWLock
1862 * subsystem has been initialized (e.g., during early startup failures).
1863 * In that case, num_held_lwlocks will be 0 and we do nothing.
1864 */
1865void
1867{
1868 while (num_held_lwlocks > 0)
1869 {
1870 HOLD_INTERRUPTS(); /* match the upcoming RESUME_INTERRUPTS */
1871
1873 }
1874
1876}
1877
1878
1879/*
1880 * LWLockHeldByMe - test whether my process holds a lock in any mode
1881 *
1882 * This is meant as debug support only.
1883 */
1884bool
1886{
1887 int i;
1888
1889 for (i = 0; i < num_held_lwlocks; i++)
1890 {
1891 if (held_lwlocks[i].lock == lock)
1892 return true;
1893 }
1894 return false;
1895}
1896
1897/*
1898 * LWLockAnyHeldByMe - test whether my process holds any of an array of locks
1899 *
1900 * This is meant as debug support only.
1901 */
1902bool
1903LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride)
1904{
1905 char *held_lock_addr;
1906 char *begin;
1907 char *end;
1908 int i;
1909
1910 begin = (char *) lock;
1911 end = begin + nlocks * stride;
1912 for (i = 0; i < num_held_lwlocks; i++)
1913 {
1914 held_lock_addr = (char *) held_lwlocks[i].lock;
1915 if (held_lock_addr >= begin &&
1916 held_lock_addr < end &&
1917 (held_lock_addr - begin) % stride == 0)
1918 return true;
1919 }
1920 return false;
1921}
1922
1923/*
1924 * LWLockHeldByMeInMode - test whether my process holds a lock in given mode
1925 *
1926 * This is meant as debug support only.
1927 */
1928bool
1930{
1931 int i;
1932
1933 for (i = 0; i < num_held_lwlocks; i++)
1934 {
1935 if (held_lwlocks[i].lock == lock && held_lwlocks[i].mode == mode)
1936 return true;
1937 }
1938 return false;
1939}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
static uint32 pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
Definition atomics.h:396
static bool pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
Definition atomics.h:349
static uint32 pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
Definition atomics.h:410
static uint32 pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
Definition atomics.h:439
static uint32 pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
Definition atomics.h:381
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition atomics.h:219
#define pg_write_barrier()
Definition atomics.h:155
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition atomics.h:366
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition atomics.h:237
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:467
static uint64 pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
Definition atomics.h:513
#define likely(x)
Definition c.h:437
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:249
#define Assert(condition)
Definition c.h:943
uint64_t uint64
Definition c.h:625
uint16_t uint16
Definition c.h:623
#define pg_unreachable()
Definition c.h:367
uint32_t uint32
Definition c.h:624
#define lengthof(array)
Definition c.h:873
#define MemSet(start, val, len)
Definition c.h:1107
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1008
uint32 result
#define fprintf(file, fmt, msg)
Definition cubescan.l:21
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
Datum arg
Definition elog.c:1322
int errcode(int sqlerrcode)
Definition elog.c:874
int int errhidestmt(bool hide_stmt)
#define LOG
Definition elog.h:32
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define FATAL
Definition elog.h:42
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define PANIC
Definition elog.h:44
#define ERROR
Definition elog.h:40
int errhidecontext(bool hide_ctx)
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
int MyProcPid
Definition globals.c:49
ProcNumber MyProcNumber
Definition globals.c:92
bool IsUnderPostmaster
Definition globals.c:122
bool IsPostmasterEnvironment
Definition globals.c:121
#define newval
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_CONTEXT
Definition hsearch.h:97
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
long val
Definition informix.c:689
static struct @177 value
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
#define LW_VAL_EXCLUSIVE
Definition lwlock.c:103
void LWLockUpdateVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val)
Definition lwlock.c:1702
static void LWLockWakeup(LWLock *lock)
Definition lwlock.c:904
#define LW_FLAG_LOCKED
Definition lwlock.c:98
bool LWLockHeldByMe(LWLock *lock)
Definition lwlock.c:1885
static LWLockHandle held_lwlocks[MAX_SIMUL_LWLOCKS]
Definition lwlock.c:167
void LWLockReleaseClearVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val)
Definition lwlock.c:1840
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
#define MAX_USER_DEFINED_TRANCHES
Definition lwlock.c:170
static List * NamedLWLockTrancheRequests
Definition lwlock.c:211
int LWLockNewTrancheId(const char *name)
Definition lwlock.c:562
#define LW_VAL_SHARED
Definition lwlock.c:104
static bool LWLockAttemptLock(LWLock *lock, LWLockMode mode)
Definition lwlock.c:764
static void LWLockWaitListLock(LWLock *lock)
Definition lwlock.c:835
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition lwlock.c:522
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1929
static LWLockTrancheShmemData * LWLockTranches
Definition lwlock.c:195
static void LWLockReportWaitEnd(void)
Definition lwlock.c:700
static void LWLockShmemRequest(void *arg)
Definition lwlock.c:416
bool LWLockWaitForVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval, uint64 *newval)
Definition lwlock.c:1566
static const char * GetLWTrancheName(uint16 trancheId)
Definition lwlock.c:709
#define LW_LOCK_MASK
Definition lwlock.c:108
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition lwlock.c:620
#define LW_FLAG_MASK
Definition lwlock.c:100
static int LocalNumUserDefinedTranches
Definition lwlock.c:198
#define LW_FLAG_HAS_WAITERS
Definition lwlock.c:96
#define MAX_SIMUL_LWLOCKS
Definition lwlock.c:157
static int NumLWLocksForNamedTranches(void)
Definition lwlock.c:400
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
#define T_NAME(lock)
Definition lwlock.c:229
static int num_held_lwlocks
Definition lwlock.c:166
void LWLockReleaseAll(void)
Definition lwlock.c:1866
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition lwlock.c:670
static const char *const BuiltinTrancheNames[]
Definition lwlock.c:137
static void LWLockWaitListUnlock(LWLock *lock)
Definition lwlock.c:891
#define LOG_LWDEBUG(a, b, c)
Definition lwlock.c:294
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1321
bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1378
static void LWLockQueueSelf(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1018
#define PRINT_LWDEBUG(a, b, c)
Definition lwlock.c:293
static void LWLockReportWaitStart(LWLock *lock)
Definition lwlock.c:691
LWLockPadded * MainLWLockArray
Definition lwlock.c:150
static int num_main_array_locks
Definition lwlock.c:214
const ShmemCallbacks LWLockCallbacks
Definition lwlock.c:219
#define LW_FLAG_WAKE_IN_PROGRESS
Definition lwlock.c:97
const char * GetLWLockIdentifier(uint32 classId, uint16 eventId)
Definition lwlock.c:747
static void LWLockDequeueSelf(LWLock *lock)
Definition lwlock.c:1061
bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride)
Definition lwlock.c:1903
static void LWLockShmemInit(void *arg)
Definition lwlock.c:445
#define LW_SHARED_MASK
Definition lwlock.c:107
static bool LWLockConflictsWithVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval, uint64 *newval, bool *result)
Definition lwlock.c:1505
void InitLWLockAccess(void)
Definition lwlock.c:506
@ LW_WS_NOT_WAITING
Definition lwlock.h:30
@ LW_WS_WAITING
Definition lwlock.h:31
@ LW_WS_PENDING_WAKEUP
Definition lwlock.h:32
#define BUFFER_MAPPING_LWLOCK_OFFSET
Definition lwlock.h:94
#define NUM_LOCK_PARTITIONS
Definition lwlock.h:87
@ LWTRANCHE_FIRST_USER_DEFINED
Definition lwlock.h:172
#define LOCK_MANAGER_LWLOCK_OFFSET
Definition lwlock.h:95
#define NUM_BUFFER_PARTITIONS
Definition lwlock.h:83
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
Definition lwlock.h:97
#define NUM_FIXED_LWLOCKS
Definition lwlock.h:99
LWLockMode
Definition lwlock.h:103
@ LW_SHARED
Definition lwlock.h:105
@ LW_WAIT_UNTIL_FREE
Definition lwlock.h:106
@ LW_EXCLUSIVE
Definition lwlock.h:104
#define NUM_PREDICATELOCK_PARTITIONS
Definition lwlock.h:91
void * palloc0(Size size)
Definition mcxt.c:1417
MemoryContext TopMemoryContext
Definition mcxt.c:166
MemoryContext PostmasterContext
Definition mcxt.c:168
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
Definition mcxt.c:743
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define RESUME_INTERRUPTS()
Definition miscadmin.h:138
#define HOLD_INTERRUPTS()
Definition miscadmin.h:136
bool process_shmem_requests_in_progress
Definition miscinit.c:1792
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static PgChecksumMode mode
#define NAMEDATALEN
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
void PGSemaphoreUnlock(PGSemaphore sema)
Definition posix_sema.c:333
void PGSemaphoreLock(PGSemaphore sema)
Definition posix_sema.c:313
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define GetPGProcByNumber(n)
Definition proc.h:504
#define proclist_delete(list, procno, link_member)
Definition proclist.h:187
static void proclist_init(proclist_head *list)
Definition proclist.h:29
#define proclist_push_tail(list, procno, link_member)
Definition proclist.h:191
#define proclist_push_head(list, procno, link_member)
Definition proclist.h:189
#define proclist_foreach_modify(iter, lhead, link_member)
Definition proclist.h:206
static bool proclist_is_empty(const proclist_head *list)
Definition proclist.h:38
#define MAX_BACKENDS
Definition procnumber.h:39
tree ctl
Definition radixtree.h:1838
void perform_spin_delay(SpinDelayStatus *status)
Definition s_lock.c:126
void finish_spin_delay(SpinDelayStatus *status)
Definition s_lock.c:186
#define init_local_spin_delay(status)
Definition s_lock.h:749
#define SHMEM_ATTACH_UNKNOWN_SIZE
Definition shmem.h:69
#define ShmemRequestStruct(...)
Definition shmem.h:176
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
PGPROC * MyProc
Definition proc.c:71
LWLockMode mode
Definition lwlock.c:163
LWLock * lock
Definition lwlock.c:162
struct LWLockTrancheShmemData::@23 user_defined[MAX_USER_DEFINED_TRANCHES]
char name[NAMEDATALEN]
Definition lwlock.c:180
pg_atomic_uint32 state
Definition lwlock.h:44
uint16 tranche
Definition lwlock.h:43
proclist_head waiters
Definition lwlock.h:45
Definition pg_list.h:54
char tranche_name[NAMEDATALEN]
Definition lwlock.c:207
Definition proc.h:179
uint8 lwWaitMode
Definition proc.h:284
PGSemaphore sem
Definition proc.h:258
uint8 lwWaiting
Definition proc.h:283
ShmemRequestCallback request_fn
Definition shmem.h:133
#define PG_WAIT_LWLOCK
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition wait_event.h:67
static void pgstat_report_wait_end(void)
Definition wait_event.h:83
const char * name
static TimestampTz wakeup[NUM_WALRCV_WAKEUPS]