Line data Source code
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-2017, 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 it's
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 "pgstat.h"
81 : #include "pg_trace.h"
82 : #include "postmaster/postmaster.h"
83 : #include "replication/slot.h"
84 : #include "storage/ipc.h"
85 : #include "storage/predicate.h"
86 : #include "storage/proc.h"
87 : #include "storage/proclist.h"
88 : #include "storage/spin.h"
89 : #include "utils/memutils.h"
90 :
91 : #ifdef LWLOCK_STATS
92 : #include "utils/hsearch.h"
93 : #endif
94 :
95 :
96 : /* We use the ShmemLock spinlock to protect LWLockCounter */
97 : extern slock_t *ShmemLock;
98 :
99 : #define LW_FLAG_HAS_WAITERS ((uint32) 1 << 30)
100 : #define LW_FLAG_RELEASE_OK ((uint32) 1 << 29)
101 : #define LW_FLAG_LOCKED ((uint32) 1 << 28)
102 :
103 : #define LW_VAL_EXCLUSIVE ((uint32) 1 << 24)
104 : #define LW_VAL_SHARED 1
105 :
106 : #define LW_LOCK_MASK ((uint32) ((1 << 25)-1))
107 : /* Must be greater than MAX_BACKENDS - which is 2^23-1, so we're fine. */
108 : #define LW_SHARED_MASK ((uint32) ((1 << 24)-1))
109 :
110 : /*
111 : * This is indexed by tranche ID and stores the names of all tranches known
112 : * to the current backend.
113 : */
114 : static char **LWLockTrancheArray = NULL;
115 : static int LWLockTranchesAllocated = 0;
116 :
117 : #define T_NAME(lock) \
118 : (LWLockTrancheArray[(lock)->tranche])
119 :
120 : /*
121 : * This points to the main array of LWLocks in shared memory. Backends inherit
122 : * the pointer by fork from the postmaster (except in the EXEC_BACKEND case,
123 : * where we have special measures to pass it down).
124 : */
125 : LWLockPadded *MainLWLockArray = NULL;
126 :
127 : /*
128 : * We use this structure to keep track of locked LWLocks for release
129 : * during error recovery. Normally, only a few will be held at once, but
130 : * occasionally the number can be much higher; for example, the pg_buffercache
131 : * extension locks all buffer partitions simultaneously.
132 : */
133 : #define MAX_SIMUL_LWLOCKS 200
134 :
135 : /* struct representing the LWLocks we're holding */
136 : typedef struct LWLockHandle
137 : {
138 : LWLock *lock;
139 : LWLockMode mode;
140 : } LWLockHandle;
141 :
142 : static int num_held_lwlocks = 0;
143 : static LWLockHandle held_lwlocks[MAX_SIMUL_LWLOCKS];
144 :
145 : /* struct representing the LWLock tranche request for named tranche */
146 : typedef struct NamedLWLockTrancheRequest
147 : {
148 : char tranche_name[NAMEDATALEN];
149 : int num_lwlocks;
150 : } NamedLWLockTrancheRequest;
151 :
152 : NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;
153 : static int NamedLWLockTrancheRequestsAllocated = 0;
154 : int NamedLWLockTrancheRequests = 0;
155 :
156 : NamedLWLockTranche *NamedLWLockTrancheArray = NULL;
157 :
158 : static bool lock_named_request_allowed = true;
159 :
160 : static void InitializeLWLocks(void);
161 : static void RegisterLWLockTranches(void);
162 :
163 : static inline void LWLockReportWaitStart(LWLock *lock);
164 : static inline void LWLockReportWaitEnd(void);
165 :
166 : #ifdef LWLOCK_STATS
167 : typedef struct lwlock_stats_key
168 : {
169 : int tranche;
170 : void *instance;
171 : } lwlock_stats_key;
172 :
173 : typedef struct lwlock_stats
174 : {
175 : lwlock_stats_key key;
176 : int sh_acquire_count;
177 : int ex_acquire_count;
178 : int block_count;
179 : int dequeue_self_count;
180 : int spin_delay_count;
181 : } lwlock_stats;
182 :
183 : static HTAB *lwlock_stats_htab;
184 : static lwlock_stats lwlock_stats_dummy;
185 : #endif
186 :
187 : #ifdef LOCK_DEBUG
188 : bool Trace_lwlocks = false;
189 :
190 : inline static void
191 : PRINT_LWDEBUG(const char *where, LWLock *lock, LWLockMode mode)
192 : {
193 : /* hide statement & context here, otherwise the log is just too verbose */
194 : if (Trace_lwlocks)
195 : {
196 : uint32 state = pg_atomic_read_u32(&lock->state);
197 :
198 : ereport(LOG,
199 : (errhidestmt(true),
200 : errhidecontext(true),
201 : errmsg_internal("%d: %s(%s %p): excl %u shared %u haswaiters %u waiters %u rOK %d",
202 : MyProcPid,
203 : where, T_NAME(lock), lock,
204 : (state & LW_VAL_EXCLUSIVE) != 0,
205 : state & LW_SHARED_MASK,
206 : (state & LW_FLAG_HAS_WAITERS) != 0,
207 : pg_atomic_read_u32(&lock->nwaiters),
208 : (state & LW_FLAG_RELEASE_OK) != 0)));
209 : }
210 : }
211 :
212 : inline static void
213 : LOG_LWDEBUG(const char *where, LWLock *lock, const char *msg)
214 : {
215 : /* hide statement & context here, otherwise the log is just too verbose */
216 : if (Trace_lwlocks)
217 : {
218 : ereport(LOG,
219 : (errhidestmt(true),
220 : errhidecontext(true),
221 : errmsg_internal("%s(%s %p): %s", where,
222 : T_NAME(lock), lock, msg)));
223 : }
224 : }
225 :
226 : #else /* not LOCK_DEBUG */
227 : #define PRINT_LWDEBUG(a,b,c) ((void)0)
228 : #define LOG_LWDEBUG(a,b,c) ((void)0)
229 : #endif /* LOCK_DEBUG */
230 :
231 : #ifdef LWLOCK_STATS
232 :
233 : static void init_lwlock_stats(void);
234 : static void print_lwlock_stats(int code, Datum arg);
235 : static lwlock_stats * get_lwlock_stats_entry(LWLock *lockid);
236 :
237 : static void
238 : init_lwlock_stats(void)
239 : {
240 : HASHCTL ctl;
241 : static MemoryContext lwlock_stats_cxt = NULL;
242 : static bool exit_registered = false;
243 :
244 : if (lwlock_stats_cxt != NULL)
245 : MemoryContextDelete(lwlock_stats_cxt);
246 :
247 : /*
248 : * The LWLock stats will be updated within a critical section, which
249 : * requires allocating new hash entries. Allocations within a critical
250 : * section are normally not allowed because running out of memory would
251 : * lead to a PANIC, but LWLOCK_STATS is debugging code that's not normally
252 : * turned on in production, so that's an acceptable risk. The hash entries
253 : * are small, so the risk of running out of memory is minimal in practice.
254 : */
255 : lwlock_stats_cxt = AllocSetContextCreate(TopMemoryContext,
256 : "LWLock stats",
257 : ALLOCSET_DEFAULT_SIZES);
258 : MemoryContextAllowInCriticalSection(lwlock_stats_cxt, true);
259 :
260 : MemSet(&ctl, 0, sizeof(ctl));
261 : ctl.keysize = sizeof(lwlock_stats_key);
262 : ctl.entrysize = sizeof(lwlock_stats);
263 : ctl.hcxt = lwlock_stats_cxt;
264 : lwlock_stats_htab = hash_create("lwlock stats", 16384, &ctl,
265 : HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
266 : if (!exit_registered)
267 : {
268 : on_shmem_exit(print_lwlock_stats, 0);
269 : exit_registered = true;
270 : }
271 : }
272 :
273 : static void
274 : print_lwlock_stats(int code, Datum arg)
275 : {
276 : HASH_SEQ_STATUS scan;
277 : lwlock_stats *lwstats;
278 :
279 : hash_seq_init(&scan, lwlock_stats_htab);
280 :
281 : /* Grab an LWLock to keep different backends from mixing reports */
282 : LWLockAcquire(&MainLWLockArray[0].lock, LW_EXCLUSIVE);
283 :
284 : while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL)
285 : {
286 : fprintf(stderr,
287 : "PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n",
288 : MyProcPid, LWLockTrancheArray[lwstats->key.tranche],
289 : lwstats->key.instance, lwstats->sh_acquire_count,
290 : lwstats->ex_acquire_count, lwstats->block_count,
291 : lwstats->spin_delay_count, lwstats->dequeue_self_count);
292 : }
293 :
294 : LWLockRelease(&MainLWLockArray[0].lock);
295 : }
296 :
297 : static lwlock_stats *
298 : get_lwlock_stats_entry(LWLock *lock)
299 : {
300 : lwlock_stats_key key;
301 : lwlock_stats *lwstats;
302 : bool found;
303 :
304 : /*
305 : * During shared memory initialization, the hash table doesn't exist yet.
306 : * Stats of that phase aren't very interesting, so just collect operations
307 : * on all locks in a single dummy entry.
308 : */
309 : if (lwlock_stats_htab == NULL)
310 : return &lwlock_stats_dummy;
311 :
312 : /* Fetch or create the entry. */
313 : key.tranche = lock->tranche;
314 : key.instance = lock;
315 : lwstats = hash_search(lwlock_stats_htab, &key, HASH_ENTER, &found);
316 : if (!found)
317 : {
318 : lwstats->sh_acquire_count = 0;
319 : lwstats->ex_acquire_count = 0;
320 : lwstats->block_count = 0;
321 : lwstats->dequeue_self_count = 0;
322 : lwstats->spin_delay_count = 0;
323 : }
324 : return lwstats;
325 : }
326 : #endif /* LWLOCK_STATS */
327 :
328 :
329 : /*
330 : * Compute number of LWLocks required by named tranches. These will be
331 : * allocated in the main array.
332 : */
333 : static int
334 15 : NumLWLocksByNamedTranches(void)
335 : {
336 15 : int numLocks = 0;
337 : int i;
338 :
339 15 : for (i = 0; i < NamedLWLockTrancheRequests; i++)
340 0 : numLocks += NamedLWLockTrancheRequestArray[i].num_lwlocks;
341 :
342 15 : return numLocks;
343 : }
344 :
345 : /*
346 : * Compute shmem space needed for LWLocks and named tranches.
347 : */
348 : Size
349 10 : LWLockShmemSize(void)
350 : {
351 : Size size;
352 : int i;
353 10 : int numLocks = NUM_FIXED_LWLOCKS;
354 :
355 10 : numLocks += NumLWLocksByNamedTranches();
356 :
357 : /* Space for the LWLock array. */
358 10 : size = mul_size(numLocks, sizeof(LWLockPadded));
359 :
360 : /* Space for dynamic allocation counter, plus room for alignment. */
361 10 : size = add_size(size, sizeof(int) + LWLOCK_PADDED_SIZE);
362 :
363 : /* space for named tranches. */
364 10 : size = add_size(size, mul_size(NamedLWLockTrancheRequests, sizeof(NamedLWLockTranche)));
365 :
366 : /* space for name of each tranche. */
367 10 : for (i = 0; i < NamedLWLockTrancheRequests; i++)
368 0 : size = add_size(size, strlen(NamedLWLockTrancheRequestArray[i].tranche_name) + 1);
369 :
370 : /* Disallow named LWLocks' requests after startup */
371 10 : lock_named_request_allowed = false;
372 :
373 10 : return size;
374 : }
375 :
376 : /*
377 : * Allocate shmem space for the main LWLock array and all tranches and
378 : * initialize it. We also register all the LWLock tranches here.
379 : */
380 : void
381 5 : CreateLWLocks(void)
382 : {
383 5 : StaticAssertExpr(LW_VAL_EXCLUSIVE > (uint32) MAX_BACKENDS,
384 : "MAX_BACKENDS too big for lwlock.c");
385 :
386 5 : StaticAssertExpr(sizeof(LWLock) <= LWLOCK_MINIMAL_SIZE &&
387 : sizeof(LWLock) <= LWLOCK_PADDED_SIZE,
388 : "Miscalculated LWLock padding");
389 :
390 5 : if (!IsUnderPostmaster)
391 : {
392 5 : Size spaceLocks = LWLockShmemSize();
393 : int *LWLockCounter;
394 : char *ptr;
395 :
396 : /* Allocate space */
397 5 : ptr = (char *) ShmemAlloc(spaceLocks);
398 :
399 : /* Leave room for dynamic allocation of tranches */
400 5 : ptr += sizeof(int);
401 :
402 : /* Ensure desired alignment of LWLock array */
403 5 : ptr += LWLOCK_PADDED_SIZE - ((uintptr_t) ptr) % LWLOCK_PADDED_SIZE;
404 :
405 5 : MainLWLockArray = (LWLockPadded *) ptr;
406 :
407 : /*
408 : * Initialize the dynamic-allocation counter for tranches, which is
409 : * stored just before the first LWLock.
410 : */
411 5 : LWLockCounter = (int *) ((char *) MainLWLockArray - sizeof(int));
412 5 : *LWLockCounter = LWTRANCHE_FIRST_USER_DEFINED;
413 :
414 : /* Initialize all LWLocks */
415 5 : InitializeLWLocks();
416 : }
417 :
418 : /* Register all LWLock tranches */
419 5 : RegisterLWLockTranches();
420 5 : }
421 :
422 : /*
423 : * Initialize LWLocks that are fixed and those belonging to named tranches.
424 : */
425 : static void
426 5 : InitializeLWLocks(void)
427 : {
428 5 : int numNamedLocks = NumLWLocksByNamedTranches();
429 : int id;
430 : int i;
431 : int j;
432 : LWLockPadded *lock;
433 :
434 : /* Initialize all individual LWLocks in main array */
435 235 : for (id = 0, lock = MainLWLockArray; id < NUM_INDIVIDUAL_LWLOCKS; id++, lock++)
436 230 : LWLockInitialize(&lock->lock, id);
437 :
438 : /* Initialize buffer mapping LWLocks in main array */
439 5 : lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS;
440 645 : for (id = 0; id < NUM_BUFFER_PARTITIONS; id++, lock++)
441 640 : LWLockInitialize(&lock->lock, LWTRANCHE_BUFFER_MAPPING);
442 :
443 : /* Initialize lmgrs' LWLocks in main array */
444 5 : lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS + NUM_BUFFER_PARTITIONS;
445 85 : for (id = 0; id < NUM_LOCK_PARTITIONS; id++, lock++)
446 80 : LWLockInitialize(&lock->lock, LWTRANCHE_LOCK_MANAGER);
447 :
448 : /* Initialize predicate lmgrs' LWLocks in main array */
449 5 : lock = MainLWLockArray + NUM_INDIVIDUAL_LWLOCKS +
450 5 : NUM_BUFFER_PARTITIONS + NUM_LOCK_PARTITIONS;
451 85 : for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++)
452 80 : LWLockInitialize(&lock->lock, LWTRANCHE_PREDICATE_LOCK_MANAGER);
453 :
454 : /* Initialize named tranches. */
455 5 : if (NamedLWLockTrancheRequests > 0)
456 : {
457 : char *trancheNames;
458 :
459 0 : NamedLWLockTrancheArray = (NamedLWLockTranche *)
460 0 : &MainLWLockArray[NUM_FIXED_LWLOCKS + numNamedLocks];
461 :
462 0 : trancheNames = (char *) NamedLWLockTrancheArray +
463 : (NamedLWLockTrancheRequests * sizeof(NamedLWLockTranche));
464 0 : lock = &MainLWLockArray[NUM_FIXED_LWLOCKS];
465 :
466 0 : for (i = 0; i < NamedLWLockTrancheRequests; i++)
467 : {
468 : NamedLWLockTrancheRequest *request;
469 : NamedLWLockTranche *tranche;
470 : char *name;
471 :
472 0 : request = &NamedLWLockTrancheRequestArray[i];
473 0 : tranche = &NamedLWLockTrancheArray[i];
474 :
475 0 : name = trancheNames;
476 0 : trancheNames += strlen(request->tranche_name) + 1;
477 0 : strcpy(name, request->tranche_name);
478 0 : tranche->trancheId = LWLockNewTrancheId();
479 0 : tranche->trancheName = name;
480 :
481 0 : for (j = 0; j < request->num_lwlocks; j++, lock++)
482 0 : LWLockInitialize(&lock->lock, tranche->trancheId);
483 : }
484 : }
485 5 : }
486 :
487 : /*
488 : * Register named tranches and tranches for fixed LWLocks.
489 : */
490 : static void
491 5 : RegisterLWLockTranches(void)
492 : {
493 : int i;
494 :
495 5 : if (LWLockTrancheArray == NULL)
496 : {
497 5 : LWLockTranchesAllocated = 64;
498 5 : LWLockTrancheArray = (char **)
499 5 : MemoryContextAllocZero(TopMemoryContext,
500 : LWLockTranchesAllocated * sizeof(char *));
501 5 : Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED);
502 : }
503 :
504 235 : for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; ++i)
505 230 : LWLockRegisterTranche(i, MainLWLockNames[i]);
506 :
507 5 : LWLockRegisterTranche(LWTRANCHE_BUFFER_MAPPING, "buffer_mapping");
508 5 : LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager");
509 5 : LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER,
510 : "predicate_lock_manager");
511 5 : LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA,
512 : "parallel_query_dsa");
513 5 : LWLockRegisterTranche(LWTRANCHE_TBM, "tbm");
514 :
515 : /* Register named tranches. */
516 5 : for (i = 0; i < NamedLWLockTrancheRequests; i++)
517 0 : LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId,
518 0 : NamedLWLockTrancheArray[i].trancheName);
519 5 : }
520 :
521 : /*
522 : * InitLWLockAccess - initialize backend-local state needed to hold LWLocks
523 : */
524 : void
525 338 : InitLWLockAccess(void)
526 : {
527 : #ifdef LWLOCK_STATS
528 : init_lwlock_stats();
529 : #endif
530 338 : }
531 :
532 : /*
533 : * GetNamedLWLockTranche - returns the base address of LWLock from the
534 : * specified tranche.
535 : *
536 : * Caller needs to retrieve the requested number of LWLocks starting from
537 : * the base lock address returned by this API. This can be used for
538 : * tranches that are requested by using RequestNamedLWLockTranche() API.
539 : */
540 : LWLockPadded *
541 0 : GetNamedLWLockTranche(const char *tranche_name)
542 : {
543 : int lock_pos;
544 : int i;
545 :
546 : /*
547 : * Obtain the position of base address of LWLock belonging to requested
548 : * tranche_name in MainLWLockArray. LWLocks for named tranches are placed
549 : * in MainLWLockArray after fixed locks.
550 : */
551 0 : lock_pos = NUM_FIXED_LWLOCKS;
552 0 : for (i = 0; i < NamedLWLockTrancheRequests; i++)
553 : {
554 0 : if (strcmp(NamedLWLockTrancheRequestArray[i].tranche_name,
555 : tranche_name) == 0)
556 0 : return &MainLWLockArray[lock_pos];
557 :
558 0 : lock_pos += NamedLWLockTrancheRequestArray[i].num_lwlocks;
559 : }
560 :
561 0 : if (i >= NamedLWLockTrancheRequests)
562 0 : elog(ERROR, "requested tranche is not registered");
563 :
564 : /* just to keep compiler quiet */
565 0 : return NULL;
566 : }
567 :
568 : /*
569 : * Allocate a new tranche ID.
570 : */
571 : int
572 0 : LWLockNewTrancheId(void)
573 : {
574 : int result;
575 : int *LWLockCounter;
576 :
577 0 : LWLockCounter = (int *) ((char *) MainLWLockArray - sizeof(int));
578 0 : SpinLockAcquire(ShmemLock);
579 0 : result = (*LWLockCounter)++;
580 0 : SpinLockRelease(ShmemLock);
581 :
582 0 : return result;
583 : }
584 :
585 : /*
586 : * Register a tranche ID in the lookup table for the current process. This
587 : * routine will save a pointer to the tranche name passed as an argument,
588 : * so the name should be allocated in a backend-lifetime context
589 : * (TopMemoryContext, static variable, or similar).
590 : */
591 : void
592 320 : LWLockRegisterTranche(int tranche_id, char *tranche_name)
593 : {
594 320 : Assert(LWLockTrancheArray != NULL);
595 :
596 320 : if (tranche_id >= LWLockTranchesAllocated)
597 : {
598 0 : int i = LWLockTranchesAllocated;
599 0 : int j = LWLockTranchesAllocated;
600 :
601 0 : while (i <= tranche_id)
602 0 : i *= 2;
603 :
604 0 : LWLockTrancheArray = (char **)
605 0 : repalloc(LWLockTrancheArray, i * sizeof(char *));
606 0 : LWLockTranchesAllocated = i;
607 0 : while (j < LWLockTranchesAllocated)
608 0 : LWLockTrancheArray[j++] = NULL;
609 : }
610 :
611 320 : LWLockTrancheArray[tranche_id] = tranche_name;
612 320 : }
613 :
614 : /*
615 : * RequestNamedLWLockTranche
616 : * Request that extra LWLocks be allocated during postmaster
617 : * startup.
618 : *
619 : * This is only useful for extensions if called from the _PG_init hook
620 : * of a library that is loaded into the postmaster via
621 : * shared_preload_libraries. Once shared memory has been allocated, calls
622 : * will be ignored. (We could raise an error, but it seems better to make
623 : * it a no-op, so that libraries containing such calls can be reloaded if
624 : * needed.)
625 : */
626 : void
627 0 : RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
628 : {
629 : NamedLWLockTrancheRequest *request;
630 :
631 0 : if (IsUnderPostmaster || !lock_named_request_allowed)
632 0 : return; /* too late */
633 :
634 0 : if (NamedLWLockTrancheRequestArray == NULL)
635 : {
636 0 : NamedLWLockTrancheRequestsAllocated = 16;
637 0 : NamedLWLockTrancheRequestArray = (NamedLWLockTrancheRequest *)
638 0 : MemoryContextAlloc(TopMemoryContext,
639 : NamedLWLockTrancheRequestsAllocated
640 : * sizeof(NamedLWLockTrancheRequest));
641 : }
642 :
643 0 : if (NamedLWLockTrancheRequests >= NamedLWLockTrancheRequestsAllocated)
644 : {
645 0 : int i = NamedLWLockTrancheRequestsAllocated;
646 :
647 0 : while (i <= NamedLWLockTrancheRequests)
648 0 : i *= 2;
649 :
650 0 : NamedLWLockTrancheRequestArray = (NamedLWLockTrancheRequest *)
651 0 : repalloc(NamedLWLockTrancheRequestArray,
652 : i * sizeof(NamedLWLockTrancheRequest));
653 0 : NamedLWLockTrancheRequestsAllocated = i;
654 : }
655 :
656 0 : request = &NamedLWLockTrancheRequestArray[NamedLWLockTrancheRequests];
657 0 : Assert(strlen(tranche_name) + 1 < NAMEDATALEN);
658 0 : StrNCpy(request->tranche_name, tranche_name, NAMEDATALEN);
659 0 : request->num_lwlocks = num_lwlocks;
660 0 : NamedLWLockTrancheRequests++;
661 : }
662 :
663 : /*
664 : * LWLockInitialize - initialize a new lwlock; it's initially unlocked
665 : */
666 : void
667 136107 : LWLockInitialize(LWLock *lock, int tranche_id)
668 : {
669 136107 : pg_atomic_init_u32(&lock->state, LW_FLAG_RELEASE_OK);
670 : #ifdef LOCK_DEBUG
671 : pg_atomic_init_u32(&lock->nwaiters, 0);
672 : #endif
673 136107 : lock->tranche = tranche_id;
674 136107 : proclist_init(&lock->waiters);
675 136107 : }
676 :
677 : /*
678 : * Report start of wait event for light-weight locks.
679 : *
680 : * This function will be used by all the light-weight lock calls which
681 : * needs to wait to acquire the lock. This function distinguishes wait
682 : * event based on tranche and lock id.
683 : */
684 : static inline void
685 946 : LWLockReportWaitStart(LWLock *lock)
686 : {
687 946 : pgstat_report_wait_start(PG_WAIT_LWLOCK | lock->tranche);
688 946 : }
689 :
690 : /*
691 : * Report end of wait event for light-weight locks.
692 : */
693 : static inline void
694 946 : LWLockReportWaitEnd(void)
695 : {
696 946 : pgstat_report_wait_end();
697 946 : }
698 :
699 : /*
700 : * Return an identifier for an LWLock based on the wait class and event.
701 : */
702 : const char *
703 0 : GetLWLockIdentifier(uint32 classId, uint16 eventId)
704 : {
705 0 : Assert(classId == PG_WAIT_LWLOCK);
706 :
707 : /*
708 : * It is quite possible that user has registered tranche in one of the
709 : * backends (e.g. by allocating lwlocks in dynamic shared memory) but not
710 : * all of them, so we can't assume the tranche is registered here.
711 : */
712 0 : if (eventId >= LWLockTranchesAllocated ||
713 0 : LWLockTrancheArray[eventId] == NULL)
714 0 : return "extension";
715 :
716 0 : return LWLockTrancheArray[eventId];
717 : }
718 :
719 : /*
720 : * Internal function that tries to atomically acquire the lwlock in the passed
721 : * in mode.
722 : *
723 : * This function will not block waiting for a lock to become free - that's the
724 : * callers job.
725 : *
726 : * Returns true if the lock isn't free and we need to wait.
727 : */
728 : static bool
729 13671076 : LWLockAttemptLock(LWLock *lock, LWLockMode mode)
730 : {
731 : uint32 old_state;
732 :
733 13671076 : AssertArg(mode == LW_EXCLUSIVE || mode == LW_SHARED);
734 :
735 : /*
736 : * Read once outside the loop, later iterations will get the newer value
737 : * via compare & exchange.
738 : */
739 13671076 : old_state = pg_atomic_read_u32(&lock->state);
740 :
741 : /* loop until we've determined whether we could acquire the lock or not */
742 : while (true)
743 : {
744 : uint32 desired_state;
745 : bool lock_free;
746 :
747 13672336 : desired_state = old_state;
748 :
749 13672336 : if (mode == LW_EXCLUSIVE)
750 : {
751 6232595 : lock_free = (old_state & LW_LOCK_MASK) == 0;
752 6232595 : if (lock_free)
753 6230949 : desired_state += LW_VAL_EXCLUSIVE;
754 : }
755 : else
756 : {
757 7439741 : lock_free = (old_state & LW_VAL_EXCLUSIVE) == 0;
758 7439741 : if (lock_free)
759 7439186 : desired_state += LW_VAL_SHARED;
760 : }
761 :
762 : /*
763 : * Attempt to swap in the state we are expecting. If we didn't see
764 : * lock to be free, that's just the old value. If we saw it as free,
765 : * we'll attempt to mark it acquired. The reason that we always swap
766 : * in the value is that this doubles as a memory barrier. We could try
767 : * to be smarter and only swap in values if we saw the lock as free,
768 : * but benchmark haven't shown it as beneficial so far.
769 : *
770 : * Retry if the value changed since we last looked at it.
771 : */
772 13672336 : if (pg_atomic_compare_exchange_u32(&lock->state,
773 : &old_state, desired_state))
774 : {
775 13671076 : if (lock_free)
776 : {
777 : /* Great! Got the lock. */
778 : #ifdef LOCK_DEBUG
779 : if (mode == LW_EXCLUSIVE)
780 : lock->owner = MyProc;
781 : #endif
782 13669102 : return false;
783 : }
784 : else
785 1974 : return true; /* somebody else has the lock */
786 : }
787 1260 : }
788 : pg_unreachable();
789 : }
790 :
791 : /*
792 : * Lock the LWLock's wait list against concurrent activity.
793 : *
794 : * NB: even though the wait list is locked, non-conflicting lock operations
795 : * may still happen concurrently.
796 : *
797 : * Time spent holding mutex should be short!
798 : */
799 : static void
800 1312782 : LWLockWaitListLock(LWLock *lock)
801 : {
802 : uint32 old_state;
803 : #ifdef LWLOCK_STATS
804 : lwlock_stats *lwstats;
805 : uint32 delays = 0;
806 :
807 : lwstats = get_lwlock_stats_entry(lock);
808 : #endif
809 :
810 : while (true)
811 : {
812 : /* always try once to acquire lock directly */
813 1312782 : old_state = pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_LOCKED);
814 1312782 : if (!(old_state & LW_FLAG_LOCKED))
815 1312473 : break; /* got lock */
816 :
817 : /* and then spin without atomic operations until lock is released */
818 : {
819 : SpinDelayStatus delayStatus;
820 :
821 309 : init_local_spin_delay(&delayStatus);
822 :
823 8893 : while (old_state & LW_FLAG_LOCKED)
824 : {
825 8275 : perform_spin_delay(&delayStatus);
826 8275 : old_state = pg_atomic_read_u32(&lock->state);
827 : }
828 : #ifdef LWLOCK_STATS
829 : delays += delayStatus.delays;
830 : #endif
831 309 : finish_spin_delay(&delayStatus);
832 : }
833 :
834 : /*
835 : * Retry. The lock might obviously already be re-acquired by the time
836 : * we're attempting to get it again.
837 : */
838 309 : }
839 :
840 : #ifdef LWLOCK_STATS
841 : lwstats->spin_delay_count += delays;
842 : #endif
843 1312473 : }
844 :
845 : /*
846 : * Unlock the LWLock's wait list.
847 : *
848 : * Note that it can be more efficient to manipulate flags and release the
849 : * locks in a single atomic operation.
850 : */
851 : static void
852 1310794 : LWLockWaitListUnlock(LWLock *lock)
853 : {
854 : uint32 old_state PG_USED_FOR_ASSERTS_ONLY;
855 :
856 1310794 : old_state = pg_atomic_fetch_and_u32(&lock->state, ~LW_FLAG_LOCKED);
857 :
858 1310794 : Assert(old_state & LW_FLAG_LOCKED);
859 1310794 : }
860 :
861 : /*
862 : * Wakeup all the lockers that currently have a chance to acquire the lock.
863 : */
864 : static void
865 1679 : LWLockWakeup(LWLock *lock)
866 : {
867 : bool new_release_ok;
868 1679 : bool wokeup_somebody = false;
869 : proclist_head wakeup;
870 : proclist_mutable_iter iter;
871 :
872 1679 : proclist_init(&wakeup);
873 :
874 1679 : new_release_ok = true;
875 :
876 : /* lock wait list while collecting backends to wake up */
877 1679 : LWLockWaitListLock(lock);
878 :
879 2293 : proclist_foreach_modify(iter, &lock->waiters, lwWaitLink)
880 : {
881 1013 : PGPROC *waiter = GetPGProcByNumber(iter.cur);
882 :
883 1013 : if (wokeup_somebody && waiter->lwWaitMode == LW_EXCLUSIVE)
884 1 : continue;
885 :
886 1012 : proclist_delete(&lock->waiters, iter.cur, lwWaitLink);
887 1012 : proclist_push_tail(&wakeup, iter.cur, lwWaitLink);
888 :
889 1012 : if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE)
890 : {
891 : /*
892 : * Prevent additional wakeups until retryer gets to run. Backends
893 : * that are just waiting for the lock to become free don't retry
894 : * automatically.
895 : */
896 653 : new_release_ok = false;
897 :
898 : /*
899 : * Don't wakeup (further) exclusive locks.
900 : */
901 653 : wokeup_somebody = true;
902 : }
903 :
904 : /*
905 : * Once we've woken up an exclusive lock, there's no point in waking
906 : * up anybody else.
907 : */
908 1012 : if (waiter->lwWaitMode == LW_EXCLUSIVE)
909 399 : break;
910 : }
911 :
912 1679 : Assert(proclist_is_empty(&wakeup) || pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS);
913 :
914 : /* unset required flags, and release lock, in one fell swoop */
915 : {
916 : uint32 old_state;
917 : uint32 desired_state;
918 :
919 1679 : old_state = pg_atomic_read_u32(&lock->state);
920 : while (true)
921 : {
922 1685 : desired_state = old_state;
923 :
924 : /* compute desired flags */
925 :
926 1685 : if (new_release_ok)
927 1057 : desired_state |= LW_FLAG_RELEASE_OK;
928 : else
929 628 : desired_state &= ~LW_FLAG_RELEASE_OK;
930 :
931 1685 : if (proclist_is_empty(&wakeup))
932 824 : desired_state &= ~LW_FLAG_HAS_WAITERS;
933 :
934 1685 : desired_state &= ~LW_FLAG_LOCKED; /* release lock */
935 :
936 1685 : if (pg_atomic_compare_exchange_u32(&lock->state, &old_state,
937 : desired_state))
938 1679 : break;
939 6 : }
940 : }
941 :
942 : /* Awaken any waiters I removed from the queue. */
943 2691 : proclist_foreach_modify(iter, &wakeup, lwWaitLink)
944 : {
945 1012 : PGPROC *waiter = GetPGProcByNumber(iter.cur);
946 :
947 : LOG_LWDEBUG("LWLockRelease", lock, "release waiter");
948 1012 : proclist_delete(&wakeup, iter.cur, lwWaitLink);
949 :
950 : /*
951 : * Guarantee that lwWaiting being unset only becomes visible once the
952 : * unlink from the link has completed. Otherwise the target backend
953 : * could be woken up for other reason and enqueue for a new lock - if
954 : * that happens before the list unlink happens, the list would end up
955 : * being corrupted.
956 : *
957 : * The barrier pairs with the LWLockWaitListLock() when enqueuing for
958 : * another lock.
959 : */
960 1012 : pg_write_barrier();
961 1012 : waiter->lwWaiting = false;
962 1012 : PGSemaphoreUnlock(waiter->sem);
963 : }
964 1679 : }
965 :
966 : /*
967 : * Add ourselves to the end of the queue.
968 : *
969 : * NB: Mode can be LW_WAIT_UNTIL_FREE here!
970 : */
971 : static void
972 1548 : LWLockQueueSelf(LWLock *lock, LWLockMode mode)
973 : {
974 : /*
975 : * If we don't have a PGPROC structure, there's no way to wait. This
976 : * should never occur, since MyProc should only be null during shared
977 : * memory initialization.
978 : */
979 1548 : if (MyProc == NULL)
980 0 : elog(PANIC, "cannot wait without a PGPROC structure");
981 :
982 1548 : if (MyProc->lwWaiting)
983 0 : elog(PANIC, "queueing for lock while waiting on another one");
984 :
985 1548 : LWLockWaitListLock(lock);
986 :
987 : /* setting the flag is protected by the spinlock */
988 1548 : pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_HAS_WAITERS);
989 :
990 1548 : MyProc->lwWaiting = true;
991 1548 : MyProc->lwWaitMode = mode;
992 :
993 : /* LW_WAIT_UNTIL_FREE waiters are always at the front of the queue */
994 1548 : if (mode == LW_WAIT_UNTIL_FREE)
995 430 : proclist_push_head(&lock->waiters, MyProc->pgprocno, lwWaitLink);
996 : else
997 1118 : proclist_push_tail(&lock->waiters, MyProc->pgprocno, lwWaitLink);
998 :
999 : /* Can release the mutex now */
1000 1548 : LWLockWaitListUnlock(lock);
1001 :
1002 : #ifdef LOCK_DEBUG
1003 : pg_atomic_fetch_add_u32(&lock->nwaiters, 1);
1004 : #endif
1005 :
1006 1548 : }
1007 :
1008 : /*
1009 : * Remove ourselves from the waitlist.
1010 : *
1011 : * This is used if we queued ourselves because we thought we needed to sleep
1012 : * but, after further checking, we discovered that we don't actually need to
1013 : * do so.
1014 : */
1015 : static void
1016 602 : LWLockDequeueSelf(LWLock *lock)
1017 : {
1018 602 : bool found = false;
1019 : proclist_mutable_iter iter;
1020 :
1021 : #ifdef LWLOCK_STATS
1022 : lwlock_stats *lwstats;
1023 :
1024 : lwstats = get_lwlock_stats_entry(lock);
1025 :
1026 : lwstats->dequeue_self_count++;
1027 : #endif
1028 :
1029 602 : LWLockWaitListLock(lock);
1030 :
1031 : /*
1032 : * Can't just remove ourselves from the list, but we need to iterate over
1033 : * all entries as somebody else could have dequeued us.
1034 : */
1035 603 : proclist_foreach_modify(iter, &lock->waiters, lwWaitLink)
1036 : {
1037 537 : if (iter.cur == MyProc->pgprocno)
1038 : {
1039 536 : found = true;
1040 536 : proclist_delete(&lock->waiters, iter.cur, lwWaitLink);
1041 536 : break;
1042 : }
1043 : }
1044 :
1045 1203 : if (proclist_is_empty(&lock->waiters) &&
1046 601 : (pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS) != 0)
1047 : {
1048 601 : pg_atomic_fetch_and_u32(&lock->state, ~LW_FLAG_HAS_WAITERS);
1049 : }
1050 :
1051 : /* XXX: combine with fetch_and above? */
1052 602 : LWLockWaitListUnlock(lock);
1053 :
1054 : /* clear waiting state again, nice for debugging */
1055 602 : if (found)
1056 536 : MyProc->lwWaiting = false;
1057 : else
1058 : {
1059 66 : int extraWaits = 0;
1060 :
1061 : /*
1062 : * Somebody else dequeued us and has or will wake us up. Deal with the
1063 : * superfluous absorption of a wakeup.
1064 : */
1065 :
1066 : /*
1067 : * Reset releaseOk if somebody woke us before we removed ourselves -
1068 : * they'll have set it to false.
1069 : */
1070 66 : pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_RELEASE_OK);
1071 :
1072 : /*
1073 : * Now wait for the scheduled wakeup, otherwise our ->lwWaiting would
1074 : * get reset at some inconvenient point later. Most of the time this
1075 : * will immediately return.
1076 : */
1077 : for (;;)
1078 : {
1079 66 : PGSemaphoreLock(MyProc->sem);
1080 66 : if (!MyProc->lwWaiting)
1081 66 : break;
1082 0 : extraWaits++;
1083 0 : }
1084 :
1085 : /*
1086 : * Fix the process wait semaphore's count for any absorbed wakeups.
1087 : */
1088 132 : while (extraWaits-- > 0)
1089 0 : PGSemaphoreUnlock(MyProc->sem);
1090 : }
1091 :
1092 : #ifdef LOCK_DEBUG
1093 : {
1094 : /* not waiting anymore */
1095 : uint32 nwaiters PG_USED_FOR_ASSERTS_ONLY = pg_atomic_fetch_sub_u32(&lock->nwaiters, 1);
1096 :
1097 : Assert(nwaiters < MAX_BACKENDS);
1098 : }
1099 : #endif
1100 602 : }
1101 :
1102 : /*
1103 : * LWLockAcquire - acquire a lightweight lock in the specified mode
1104 : *
1105 : * If the lock is not available, sleep until it is. Returns true if the lock
1106 : * was available immediately, false if we had to sleep.
1107 : *
1108 : * Side effect: cancel/die interrupts are held off until lock release.
1109 : */
1110 : bool
1111 13433533 : LWLockAcquire(LWLock *lock, LWLockMode mode)
1112 : {
1113 13433533 : PGPROC *proc = MyProc;
1114 13433533 : bool result = true;
1115 13433533 : int extraWaits = 0;
1116 : #ifdef LWLOCK_STATS
1117 : lwlock_stats *lwstats;
1118 :
1119 : lwstats = get_lwlock_stats_entry(lock);
1120 : #endif
1121 :
1122 13433533 : AssertArg(mode == LW_SHARED || mode == LW_EXCLUSIVE);
1123 :
1124 : PRINT_LWDEBUG("LWLockAcquire", lock, mode);
1125 :
1126 : #ifdef LWLOCK_STATS
1127 : /* Count lock acquisition attempts */
1128 : if (mode == LW_EXCLUSIVE)
1129 : lwstats->ex_acquire_count++;
1130 : else
1131 : lwstats->sh_acquire_count++;
1132 : #endif /* LWLOCK_STATS */
1133 :
1134 : /*
1135 : * We can't wait if we haven't got a PGPROC. This should only occur
1136 : * during bootstrap or shared memory initialization. Put an Assert here
1137 : * to catch unsafe coding practices.
1138 : */
1139 13433533 : Assert(!(proc == NULL && IsUnderPostmaster));
1140 :
1141 : /* Ensure we will have room to remember the lock */
1142 13433533 : if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)
1143 0 : elog(ERROR, "too many LWLocks taken");
1144 :
1145 : /*
1146 : * Lock out cancel/die interrupts until we exit the code section protected
1147 : * by the LWLock. This ensures that interrupts will not interfere with
1148 : * manipulations of data structures in shared memory.
1149 : */
1150 13433533 : HOLD_INTERRUPTS();
1151 :
1152 : /*
1153 : * Loop here to try to acquire lock after each time we are signaled by
1154 : * LWLockRelease.
1155 : *
1156 : * NOTE: it might seem better to have LWLockRelease actually grant us the
1157 : * lock, rather than retrying and possibly having to go back to sleep. But
1158 : * in practice that is no good because it means a process swap for every
1159 : * lock acquisition when two or more processes are contending for the same
1160 : * lock. Since LWLocks are normally used to protect not-very-long
1161 : * sections of computation, a process needs to be able to acquire and
1162 : * release the same lock many times during a single CPU time slice, even
1163 : * in the presence of contention. The efficiency of being able to do that
1164 : * outweighs the inefficiency of sometimes wasting a process dispatch
1165 : * cycle because the lock is not free when a released waiter finally gets
1166 : * to run. See pgsql-hackers archives for 29-Dec-01.
1167 : */
1168 : for (;;)
1169 : {
1170 : bool mustwait;
1171 :
1172 : /*
1173 : * Try to grab the lock the first time, we're not in the waitqueue
1174 : * yet/anymore.
1175 : */
1176 13434121 : mustwait = LWLockAttemptLock(lock, mode);
1177 :
1178 13434121 : if (!mustwait)
1179 : {
1180 : LOG_LWDEBUG("LWLockAcquire", lock, "immediately acquired lock");
1181 13433003 : break; /* got the lock */
1182 : }
1183 :
1184 : /*
1185 : * Ok, at this point we couldn't grab the lock on the first try. We
1186 : * cannot simply queue ourselves to the end of the list and wait to be
1187 : * woken up because by now the lock could long have been released.
1188 : * Instead add us to the queue and try to grab the lock again. If we
1189 : * succeed we need to revert the queuing and be happy, otherwise we
1190 : * recheck the lock. If we still couldn't grab it, we know that the
1191 : * other locker will see our queue entries when releasing since they
1192 : * existed before we checked for the lock.
1193 : */
1194 :
1195 : /* add to the queue */
1196 1118 : LWLockQueueSelf(lock, mode);
1197 :
1198 : /* we're now guaranteed to be woken up if necessary */
1199 1118 : mustwait = LWLockAttemptLock(lock, mode);
1200 :
1201 : /* ok, grabbed the lock the second time round, need to undo queueing */
1202 1118 : if (!mustwait)
1203 : {
1204 : LOG_LWDEBUG("LWLockAcquire", lock, "acquired, undoing queue");
1205 :
1206 530 : LWLockDequeueSelf(lock);
1207 530 : break;
1208 : }
1209 :
1210 : /*
1211 : * Wait until awakened.
1212 : *
1213 : * Since we share the process wait semaphore with the regular lock
1214 : * manager and ProcWaitForSignal, and we may need to acquire an LWLock
1215 : * while one of those is pending, it is possible that we get awakened
1216 : * for a reason other than being signaled by LWLockRelease. If so,
1217 : * loop back and wait again. Once we've gotten the LWLock,
1218 : * re-increment the sema by the number of additional signals received,
1219 : * so that the lock manager or signal manager will see the received
1220 : * signal when it next waits.
1221 : */
1222 : LOG_LWDEBUG("LWLockAcquire", lock, "waiting");
1223 :
1224 : #ifdef LWLOCK_STATS
1225 : lwstats->block_count++;
1226 : #endif
1227 :
1228 588 : LWLockReportWaitStart(lock);
1229 : TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode);
1230 :
1231 : for (;;)
1232 : {
1233 588 : PGSemaphoreLock(proc->sem);
1234 588 : if (!proc->lwWaiting)
1235 588 : break;
1236 0 : extraWaits++;
1237 0 : }
1238 :
1239 : /* Retrying, allow LWLockRelease to release waiters again. */
1240 588 : pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_RELEASE_OK);
1241 :
1242 : #ifdef LOCK_DEBUG
1243 : {
1244 : /* not waiting anymore */
1245 : uint32 nwaiters PG_USED_FOR_ASSERTS_ONLY = pg_atomic_fetch_sub_u32(&lock->nwaiters, 1);
1246 :
1247 : Assert(nwaiters < MAX_BACKENDS);
1248 : }
1249 : #endif
1250 :
1251 : TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), mode);
1252 588 : LWLockReportWaitEnd();
1253 :
1254 : LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
1255 :
1256 : /* Now loop back and try to acquire lock again. */
1257 588 : result = false;
1258 588 : }
1259 :
1260 : TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), mode);
1261 :
1262 : /* Add lock to list of locks held by this backend */
1263 13433533 : held_lwlocks[num_held_lwlocks].lock = lock;
1264 13433533 : held_lwlocks[num_held_lwlocks++].mode = mode;
1265 :
1266 : /*
1267 : * Fix the process wait semaphore's count for any absorbed wakeups.
1268 : */
1269 26867066 : while (extraWaits-- > 0)
1270 0 : PGSemaphoreUnlock(proc->sem);
1271 :
1272 13433533 : return result;
1273 : }
1274 :
1275 : /*
1276 : * LWLockConditionalAcquire - acquire a lightweight lock in the specified mode
1277 : *
1278 : * If the lock is not available, return FALSE with no side-effects.
1279 : *
1280 : * If successful, cancel/die interrupts are held off until lock release.
1281 : */
1282 : bool
1283 226138 : LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
1284 : {
1285 : bool mustwait;
1286 :
1287 226138 : AssertArg(mode == LW_SHARED || mode == LW_EXCLUSIVE);
1288 :
1289 : PRINT_LWDEBUG("LWLockConditionalAcquire", lock, mode);
1290 :
1291 : /* Ensure we will have room to remember the lock */
1292 226138 : if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)
1293 0 : elog(ERROR, "too many LWLocks taken");
1294 :
1295 : /*
1296 : * Lock out cancel/die interrupts until we exit the code section protected
1297 : * by the LWLock. This ensures that interrupts will not interfere with
1298 : * manipulations of data structures in shared memory.
1299 : */
1300 226138 : HOLD_INTERRUPTS();
1301 :
1302 : /* Check for the lock */
1303 226138 : mustwait = LWLockAttemptLock(lock, mode);
1304 :
1305 226138 : if (mustwait)
1306 : {
1307 : /* Failed to get lock, so release interrupt holdoff */
1308 40 : RESUME_INTERRUPTS();
1309 :
1310 : LOG_LWDEBUG("LWLockConditionalAcquire", lock, "failed");
1311 : TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_FAIL(T_NAME(lock), mode);
1312 : }
1313 : else
1314 : {
1315 : /* Add lock to list of locks held by this backend */
1316 226098 : held_lwlocks[num_held_lwlocks].lock = lock;
1317 226098 : held_lwlocks[num_held_lwlocks++].mode = mode;
1318 : TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE(T_NAME(lock), mode);
1319 : }
1320 226138 : return !mustwait;
1321 : }
1322 :
1323 : /*
1324 : * LWLockAcquireOrWait - Acquire lock, or wait until it's free
1325 : *
1326 : * The semantics of this function are a bit funky. If the lock is currently
1327 : * free, it is acquired in the given mode, and the function returns true. If
1328 : * the lock isn't immediately free, the function waits until it is released
1329 : * and returns false, but does not acquire the lock.
1330 : *
1331 : * This is currently used for WALWriteLock: when a backend flushes the WAL,
1332 : * holding WALWriteLock, it can flush the commit records of many other
1333 : * backends as a side-effect. Those other backends need to wait until the
1334 : * flush finishes, but don't need to acquire the lock anymore. They can just
1335 : * wake up, observe that their records have already been flushed, and return.
1336 : */
1337 : bool
1338 9584 : LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
1339 : {
1340 9584 : PGPROC *proc = MyProc;
1341 : bool mustwait;
1342 9584 : int extraWaits = 0;
1343 : #ifdef LWLOCK_STATS
1344 : lwlock_stats *lwstats;
1345 :
1346 : lwstats = get_lwlock_stats_entry(lock);
1347 : #endif
1348 :
1349 9584 : Assert(mode == LW_SHARED || mode == LW_EXCLUSIVE);
1350 :
1351 : PRINT_LWDEBUG("LWLockAcquireOrWait", lock, mode);
1352 :
1353 : /* Ensure we will have room to remember the lock */
1354 9584 : if (num_held_lwlocks >= MAX_SIMUL_LWLOCKS)
1355 0 : elog(ERROR, "too many LWLocks taken");
1356 :
1357 : /*
1358 : * Lock out cancel/die interrupts until we exit the code section protected
1359 : * by the LWLock. This ensures that interrupts will not interfere with
1360 : * manipulations of data structures in shared memory.
1361 : */
1362 9584 : HOLD_INTERRUPTS();
1363 :
1364 : /*
1365 : * NB: We're using nearly the same twice-in-a-row lock acquisition
1366 : * protocol as LWLockAcquire(). Check its comments for details.
1367 : */
1368 9584 : mustwait = LWLockAttemptLock(lock, mode);
1369 :
1370 9584 : if (mustwait)
1371 : {
1372 115 : LWLockQueueSelf(lock, LW_WAIT_UNTIL_FREE);
1373 :
1374 115 : mustwait = LWLockAttemptLock(lock, mode);
1375 :
1376 115 : if (mustwait)
1377 : {
1378 : /*
1379 : * Wait until awakened. Like in LWLockAcquire, be prepared for
1380 : * bogus wakeups, because we share the semaphore with
1381 : * ProcWaitForSignal.
1382 : */
1383 : LOG_LWDEBUG("LWLockAcquireOrWait", lock, "waiting");
1384 :
1385 : #ifdef LWLOCK_STATS
1386 : lwstats->block_count++;
1387 : #endif
1388 :
1389 113 : LWLockReportWaitStart(lock);
1390 : TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), mode);
1391 :
1392 : for (;;)
1393 : {
1394 113 : PGSemaphoreLock(proc->sem);
1395 113 : if (!proc->lwWaiting)
1396 113 : break;
1397 0 : extraWaits++;
1398 0 : }
1399 :
1400 : #ifdef LOCK_DEBUG
1401 : {
1402 : /* not waiting anymore */
1403 : uint32 nwaiters PG_USED_FOR_ASSERTS_ONLY = pg_atomic_fetch_sub_u32(&lock->nwaiters, 1);
1404 :
1405 : Assert(nwaiters < MAX_BACKENDS);
1406 : }
1407 : #endif
1408 : TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), mode);
1409 113 : LWLockReportWaitEnd();
1410 :
1411 : LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened");
1412 : }
1413 : else
1414 : {
1415 : LOG_LWDEBUG("LWLockAcquireOrWait", lock, "acquired, undoing queue");
1416 :
1417 : /*
1418 : * Got lock in the second attempt, undo queueing. We need to treat
1419 : * this as having successfully acquired the lock, otherwise we'd
1420 : * not necessarily wake up people we've prevented from acquiring
1421 : * the lock.
1422 : */
1423 2 : LWLockDequeueSelf(lock);
1424 : }
1425 : }
1426 :
1427 : /*
1428 : * Fix the process wait semaphore's count for any absorbed wakeups.
1429 : */
1430 19168 : while (extraWaits-- > 0)
1431 0 : PGSemaphoreUnlock(proc->sem);
1432 :
1433 9584 : if (mustwait)
1434 : {
1435 : /* Failed to get lock, so release interrupt holdoff */
1436 113 : RESUME_INTERRUPTS();
1437 : LOG_LWDEBUG("LWLockAcquireOrWait", lock, "failed");
1438 : TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_FAIL(T_NAME(lock), mode);
1439 : }
1440 : else
1441 : {
1442 : LOG_LWDEBUG("LWLockAcquireOrWait", lock, "succeeded");
1443 : /* Add lock to list of locks held by this backend */
1444 9471 : held_lwlocks[num_held_lwlocks].lock = lock;
1445 9471 : held_lwlocks[num_held_lwlocks++].mode = mode;
1446 : TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT(T_NAME(lock), mode);
1447 : }
1448 :
1449 9584 : return !mustwait;
1450 : }
1451 :
1452 : /*
1453 : * Does the lwlock in its current state need to wait for the variable value to
1454 : * change?
1455 : *
1456 : * If we don't need to wait, and it's because the value of the variable has
1457 : * changed, store the current value in newval.
1458 : *
1459 : * *result is set to true if the lock was free, and false otherwise.
1460 : */
1461 : static bool
1462 83228 : LWLockConflictsWithVar(LWLock *lock,
1463 : uint64 *valptr, uint64 oldval, uint64 *newval,
1464 : bool *result)
1465 : {
1466 : bool mustwait;
1467 : uint64 value;
1468 :
1469 : /*
1470 : * Test first to see if it the slot is free right now.
1471 : *
1472 : * XXX: the caller uses a spinlock before this, so we don't need a memory
1473 : * barrier here as far as the current usage is concerned. But that might
1474 : * not be safe in general.
1475 : */
1476 83228 : mustwait = (pg_atomic_read_u32(&lock->state) & LW_VAL_EXCLUSIVE) != 0;
1477 :
1478 83228 : if (!mustwait)
1479 : {
1480 82489 : *result = true;
1481 82489 : return false;
1482 : }
1483 :
1484 739 : *result = false;
1485 :
1486 : /*
1487 : * Read value using the lwlock's wait list lock, as we can't generally
1488 : * rely on atomic 64 bit reads/stores. TODO: On platforms with a way to
1489 : * do atomic 64 bit reads/writes the spinlock should be optimized away.
1490 : */
1491 739 : LWLockWaitListLock(lock);
1492 739 : value = *valptr;
1493 739 : LWLockWaitListUnlock(lock);
1494 :
1495 739 : if (value != oldval)
1496 : {
1497 179 : mustwait = false;
1498 179 : *newval = value;
1499 : }
1500 : else
1501 : {
1502 560 : mustwait = true;
1503 : }
1504 :
1505 739 : return mustwait;
1506 : }
1507 :
1508 : /*
1509 : * LWLockWaitForVar - Wait until lock is free, or a variable is updated.
1510 : *
1511 : * If the lock is held and *valptr equals oldval, waits until the lock is
1512 : * either freed, or the lock holder updates *valptr by calling
1513 : * LWLockUpdateVar. If the lock is free on exit (immediately or after
1514 : * waiting), returns true. If the lock is still held, but *valptr no longer
1515 : * matches oldval, returns false and sets *newval to the current value in
1516 : * *valptr.
1517 : *
1518 : * Note: this function ignores shared lock holders; if the lock is held
1519 : * in shared mode, returns 'true'.
1520 : */
1521 : bool
1522 82668 : LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
1523 : {
1524 82668 : PGPROC *proc = MyProc;
1525 82668 : int extraWaits = 0;
1526 82668 : bool result = false;
1527 : #ifdef LWLOCK_STATS
1528 : lwlock_stats *lwstats;
1529 :
1530 : lwstats = get_lwlock_stats_entry(lock);
1531 : #endif
1532 :
1533 : PRINT_LWDEBUG("LWLockWaitForVar", lock, LW_WAIT_UNTIL_FREE);
1534 :
1535 : /*
1536 : * Lock out cancel/die interrupts while we sleep on the lock. There is no
1537 : * cleanup mechanism to remove us from the wait queue if we got
1538 : * interrupted.
1539 : */
1540 82668 : HOLD_INTERRUPTS();
1541 :
1542 : /*
1543 : * Loop here to check the lock's status after each time we are signaled.
1544 : */
1545 : for (;;)
1546 : {
1547 : bool mustwait;
1548 :
1549 82913 : mustwait = LWLockConflictsWithVar(lock, valptr, oldval, newval,
1550 : &result);
1551 :
1552 82913 : if (!mustwait)
1553 82598 : break; /* the lock was free or value didn't match */
1554 :
1555 : /*
1556 : * Add myself to wait queue. Note that this is racy, somebody else
1557 : * could wakeup before we're finished queuing. NB: We're using nearly
1558 : * the same twice-in-a-row lock acquisition protocol as
1559 : * LWLockAcquire(). Check its comments for details. The only
1560 : * difference is that we also have to check the variable's values when
1561 : * checking the state of the lock.
1562 : */
1563 315 : LWLockQueueSelf(lock, LW_WAIT_UNTIL_FREE);
1564 :
1565 : /*
1566 : * Set RELEASE_OK flag, to make sure we get woken up as soon as the
1567 : * lock is released.
1568 : */
1569 315 : pg_atomic_fetch_or_u32(&lock->state, LW_FLAG_RELEASE_OK);
1570 :
1571 : /*
1572 : * We're now guaranteed to be woken up if necessary. Recheck the lock
1573 : * and variables state.
1574 : */
1575 315 : mustwait = LWLockConflictsWithVar(lock, valptr, oldval, newval,
1576 : &result);
1577 :
1578 : /* Ok, no conflict after we queued ourselves. Undo queueing. */
1579 315 : if (!mustwait)
1580 : {
1581 : LOG_LWDEBUG("LWLockWaitForVar", lock, "free, undoing queue");
1582 :
1583 70 : LWLockDequeueSelf(lock);
1584 70 : break;
1585 : }
1586 :
1587 : /*
1588 : * Wait until awakened.
1589 : *
1590 : * Since we share the process wait semaphore with the regular lock
1591 : * manager and ProcWaitForSignal, and we may need to acquire an LWLock
1592 : * while one of those is pending, it is possible that we get awakened
1593 : * for a reason other than being signaled by LWLockRelease. If so,
1594 : * loop back and wait again. Once we've gotten the LWLock,
1595 : * re-increment the sema by the number of additional signals received,
1596 : * so that the lock manager or signal manager will see the received
1597 : * signal when it next waits.
1598 : */
1599 : LOG_LWDEBUG("LWLockWaitForVar", lock, "waiting");
1600 :
1601 : #ifdef LWLOCK_STATS
1602 : lwstats->block_count++;
1603 : #endif
1604 :
1605 245 : LWLockReportWaitStart(lock);
1606 : TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), LW_EXCLUSIVE);
1607 :
1608 : for (;;)
1609 : {
1610 245 : PGSemaphoreLock(proc->sem);
1611 245 : if (!proc->lwWaiting)
1612 245 : break;
1613 0 : extraWaits++;
1614 0 : }
1615 :
1616 : #ifdef LOCK_DEBUG
1617 : {
1618 : /* not waiting anymore */
1619 : uint32 nwaiters PG_USED_FOR_ASSERTS_ONLY = pg_atomic_fetch_sub_u32(&lock->nwaiters, 1);
1620 :
1621 : Assert(nwaiters < MAX_BACKENDS);
1622 : }
1623 : #endif
1624 :
1625 : TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), LW_EXCLUSIVE);
1626 245 : LWLockReportWaitEnd();
1627 :
1628 : LOG_LWDEBUG("LWLockWaitForVar", lock, "awakened");
1629 :
1630 : /* Now loop back and check the status of the lock again. */
1631 245 : }
1632 :
1633 : TRACE_POSTGRESQL_LWLOCK_ACQUIRE(T_NAME(lock), LW_EXCLUSIVE);
1634 :
1635 : /*
1636 : * Fix the process wait semaphore's count for any absorbed wakeups.
1637 : */
1638 165336 : while (extraWaits-- > 0)
1639 0 : PGSemaphoreUnlock(proc->sem);
1640 :
1641 : /*
1642 : * Now okay to allow cancel/die interrupts.
1643 : */
1644 82668 : RESUME_INTERRUPTS();
1645 :
1646 82668 : return result;
1647 : }
1648 :
1649 :
1650 : /*
1651 : * LWLockUpdateVar - Update a variable and wake up waiters atomically
1652 : *
1653 : * Sets *valptr to 'val', and wakes up all processes waiting for us with
1654 : * LWLockWaitForVar(). Setting the value and waking up the processes happen
1655 : * atomically so that any process calling LWLockWaitForVar() on the same lock
1656 : * is guaranteed to see the new value, and act accordingly.
1657 : *
1658 : * The caller must be holding the lock in exclusive mode.
1659 : */
1660 : void
1661 1103 : LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val)
1662 : {
1663 : proclist_head wakeup;
1664 : proclist_mutable_iter iter;
1665 :
1666 : PRINT_LWDEBUG("LWLockUpdateVar", lock, LW_EXCLUSIVE);
1667 :
1668 1103 : proclist_init(&wakeup);
1669 :
1670 1103 : LWLockWaitListLock(lock);
1671 :
1672 1103 : Assert(pg_atomic_read_u32(&lock->state) & LW_VAL_EXCLUSIVE);
1673 :
1674 : /* Update the lock's value */
1675 1103 : *valptr = val;
1676 :
1677 : /*
1678 : * See if there are any LW_WAIT_UNTIL_FREE waiters that need to be woken
1679 : * up. They are always in the front of the queue.
1680 : */
1681 1103 : proclist_foreach_modify(iter, &lock->waiters, lwWaitLink)
1682 : {
1683 0 : PGPROC *waiter = GetPGProcByNumber(iter.cur);
1684 :
1685 0 : if (waiter->lwWaitMode != LW_WAIT_UNTIL_FREE)
1686 0 : break;
1687 :
1688 0 : proclist_delete(&lock->waiters, iter.cur, lwWaitLink);
1689 0 : proclist_push_tail(&wakeup, iter.cur, lwWaitLink);
1690 : }
1691 :
1692 : /* We are done updating shared state of the lock itself. */
1693 1103 : LWLockWaitListUnlock(lock);
1694 :
1695 : /*
1696 : * Awaken any waiters I removed from the queue.
1697 : */
1698 1103 : proclist_foreach_modify(iter, &wakeup, lwWaitLink)
1699 : {
1700 0 : PGPROC *waiter = GetPGProcByNumber(iter.cur);
1701 :
1702 0 : proclist_delete(&wakeup, iter.cur, lwWaitLink);
1703 : /* check comment in LWLockWakeup() about this barrier */
1704 0 : pg_write_barrier();
1705 0 : waiter->lwWaiting = false;
1706 0 : PGSemaphoreUnlock(waiter->sem);
1707 : }
1708 1103 : }
1709 :
1710 :
1711 : /*
1712 : * LWLockRelease - release a previously acquired lock
1713 : */
1714 : void
1715 13669102 : LWLockRelease(LWLock *lock)
1716 : {
1717 : LWLockMode mode;
1718 : uint32 oldstate;
1719 : bool check_waiters;
1720 : int i;
1721 :
1722 : /*
1723 : * Remove lock from list of locks held. Usually, but not always, it will
1724 : * be the latest-acquired lock; so search array backwards.
1725 : */
1726 27425198 : for (i = num_held_lwlocks; --i >= 0;)
1727 13756096 : if (lock == held_lwlocks[i].lock)
1728 13669102 : break;
1729 :
1730 13669102 : if (i < 0)
1731 0 : elog(ERROR, "lock %s is not held", T_NAME(lock));
1732 :
1733 13669102 : mode = held_lwlocks[i].mode;
1734 :
1735 13669102 : num_held_lwlocks--;
1736 13756096 : for (; i < num_held_lwlocks; i++)
1737 86994 : held_lwlocks[i] = held_lwlocks[i + 1];
1738 :
1739 : PRINT_LWDEBUG("LWLockRelease", lock, mode);
1740 :
1741 : /*
1742 : * Release my hold on lock, after that it can immediately be acquired by
1743 : * others, even if we still have to wakeup other waiters.
1744 : */
1745 13669102 : if (mode == LW_EXCLUSIVE)
1746 6230779 : oldstate = pg_atomic_sub_fetch_u32(&lock->state, LW_VAL_EXCLUSIVE);
1747 : else
1748 7438323 : oldstate = pg_atomic_sub_fetch_u32(&lock->state, LW_VAL_SHARED);
1749 :
1750 : /* nobody else can have that kind of lock */
1751 13669102 : Assert(!(oldstate & LW_VAL_EXCLUSIVE));
1752 :
1753 :
1754 : /*
1755 : * We're still waiting for backends to get scheduled, don't wake them up
1756 : * again.
1757 : */
1758 13669102 : if ((oldstate & (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK)) ==
1759 1713 : (LW_FLAG_HAS_WAITERS | LW_FLAG_RELEASE_OK) &&
1760 1713 : (oldstate & LW_LOCK_MASK) == 0)
1761 1679 : check_waiters = true;
1762 : else
1763 13667423 : check_waiters = false;
1764 :
1765 : /*
1766 : * As waking up waiters requires the spinlock to be acquired, only do so
1767 : * if necessary.
1768 : */
1769 13669102 : if (check_waiters)
1770 : {
1771 : /* XXX: remove before commit? */
1772 : LOG_LWDEBUG("LWLockRelease", lock, "releasing waiters");
1773 1679 : LWLockWakeup(lock);
1774 : }
1775 :
1776 : TRACE_POSTGRESQL_LWLOCK_RELEASE(T_NAME(lock));
1777 :
1778 : /*
1779 : * Now okay to allow cancel/die interrupts.
1780 : */
1781 13669102 : RESUME_INTERRUPTS();
1782 13669102 : }
1783 :
1784 : /*
1785 : * LWLockReleaseClearVar - release a previously acquired lock, reset variable
1786 : */
1787 : void
1788 1306802 : LWLockReleaseClearVar(LWLock *lock, uint64 *valptr, uint64 val)
1789 : {
1790 1306802 : LWLockWaitListLock(lock);
1791 :
1792 : /*
1793 : * Set the variable's value before releasing the lock, that prevents race
1794 : * a race condition wherein a new locker acquires the lock, but hasn't yet
1795 : * set the variables value.
1796 : */
1797 1306802 : *valptr = val;
1798 1306802 : LWLockWaitListUnlock(lock);
1799 :
1800 1306802 : LWLockRelease(lock);
1801 1306802 : }
1802 :
1803 :
1804 : /*
1805 : * LWLockReleaseAll - release all currently-held locks
1806 : *
1807 : * Used to clean up after ereport(ERROR). An important difference between this
1808 : * function and retail LWLockRelease calls is that InterruptHoldoffCount is
1809 : * unchanged by this operation. This is necessary since InterruptHoldoffCount
1810 : * has been set to an appropriate level earlier in error recovery. We could
1811 : * decrement it below zero if we allow it to drop for each released lock!
1812 : */
1813 : void
1814 3947 : LWLockReleaseAll(void)
1815 : {
1816 7903 : while (num_held_lwlocks > 0)
1817 : {
1818 9 : HOLD_INTERRUPTS(); /* match the upcoming RESUME_INTERRUPTS */
1819 :
1820 9 : LWLockRelease(held_lwlocks[num_held_lwlocks - 1].lock);
1821 : }
1822 3947 : }
1823 :
1824 :
1825 : /*
1826 : * LWLockHeldByMe - test whether my process holds a lock in any mode
1827 : *
1828 : * This is meant as debug support only.
1829 : */
1830 : bool
1831 6613612 : LWLockHeldByMe(LWLock *l)
1832 : {
1833 : int i;
1834 :
1835 7029620 : for (i = 0; i < num_held_lwlocks; i++)
1836 : {
1837 1134939 : if (held_lwlocks[i].lock == l)
1838 718931 : return true;
1839 : }
1840 5894681 : return false;
1841 : }
1842 :
1843 : /*
1844 : * LWLockHeldByMeInMode - test whether my process holds a lock in given mode
1845 : *
1846 : * This is meant as debug support only.
1847 : */
1848 : bool
1849 1452367 : LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
1850 : {
1851 : int i;
1852 :
1853 1653351 : for (i = 0; i < num_held_lwlocks; i++)
1854 : {
1855 1653351 : if (held_lwlocks[i].lock == l && held_lwlocks[i].mode == mode)
1856 1452367 : return true;
1857 : }
1858 0 : return false;
1859 : }
|