94#define LW_FLAG_HAS_WAITERS ((uint32) 1 << 30)
95#define LW_FLAG_RELEASE_OK ((uint32) 1 << 29)
96#define LW_FLAG_LOCKED ((uint32) 1 << 28)
98#define LW_VAL_EXCLUSIVE ((uint32) 1 << 24)
99#define LW_VAL_SHARED 1
101#define LW_LOCK_MASK ((uint32) ((1 << 25)-1))
103#define LW_SHARED_MASK ((uint32) ((1 << 24)-1))
106 "MAX_BACKENDS too big for lwlock.c");
127#define PG_LWLOCK(id, lockname) [id] = CppAsString(lockname),
173 "missing entries in BuiltinTrancheNames[]");
196#define MAX_SIMUL_LWLOCKS 200
234#define T_NAME(lock) \
235 GetLWTrancheName((lock)->tranche)
238typedef struct lwlock_stats_key
244typedef struct lwlock_stats
246 lwlock_stats_key
key;
247 int sh_acquire_count;
248 int ex_acquire_count;
250 int dequeue_self_count;
251 int spin_delay_count;
254static HTAB *lwlock_stats_htab;
255static lwlock_stats lwlock_stats_dummy;
259bool Trace_lwlocks =
false;
272 errmsg_internal(
"%d: %s(%s %p): excl %u shared %u haswaiters %u waiters %u rOK %d",
274 where,
T_NAME(lock), lock,
293 T_NAME(lock), lock, msg)));
298#define PRINT_LWDEBUG(a,b,c) ((void)0)
299#define LOG_LWDEBUG(a,b,c) ((void)0)
304static void init_lwlock_stats(
void);
305static void print_lwlock_stats(
int code,
Datum arg);
306static lwlock_stats * get_lwlock_stats_entry(
LWLock *lock);
309init_lwlock_stats(
void)
313 static bool exit_registered =
false;
315 if (lwlock_stats_cxt != NULL)
331 ctl.keysize =
sizeof(lwlock_stats_key);
332 ctl.entrysize =
sizeof(lwlock_stats);
333 ctl.hcxt = lwlock_stats_cxt;
336 if (!exit_registered)
339 exit_registered =
true;
344print_lwlock_stats(
int code,
Datum arg)
347 lwlock_stats *lwstats;
357 "PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n",
359 lwstats->key.instance, lwstats->sh_acquire_count,
360 lwstats->ex_acquire_count, lwstats->block_count,
361 lwstats->spin_delay_count, lwstats->dequeue_self_count);
368get_lwlock_stats_entry(
LWLock *lock)
370 lwlock_stats_key
key;
371 lwlock_stats *lwstats;
379 if (lwlock_stats_htab == NULL)
380 return &lwlock_stats_dummy;
389 lwstats->sh_acquire_count = 0;
390 lwstats->ex_acquire_count = 0;
391 lwstats->block_count = 0;
392 lwstats->dequeue_self_count = 0;
393 lwstats->spin_delay_count = 0;
499 for (
id = 0, lock =
MainLWLockArray;
id < NUM_INDIVIDUAL_LWLOCKS;
id++, lock++)
593 elog(
ERROR,
"requested tranche is not registered");
611 result = (*LWLockCounter)++;
647 newalloc *
sizeof(
char *));
675 elog(
FATAL,
"cannot request additional LWLocks outside shmem_request_hook");
802 desired_state = old_state;
828 &old_state, desired_state))
859 lwlock_stats *lwstats;
862 lwstats = get_lwlock_stats_entry(lock);
884 delays += delayStatus.
delays;
896 lwstats->spin_delay_count += delays;
923 bool wokeup_somebody =
false;
929 new_release_ok =
true;
951 new_release_ok =
false;
956 wokeup_somebody =
true;
986 desired_state = old_state;
993 desired_state &= ~LW_FLAG_RELEASE_OK;
996 desired_state &= ~LW_FLAG_HAS_WAITERS;
998 desired_state &= ~LW_FLAG_LOCKED;
1011 LOG_LWDEBUG(
"LWLockRelease", lock,
"release waiter");
1044 elog(
PANIC,
"cannot wait without a PGPROC structure");
1047 elog(
PANIC,
"queueing for lock while waiting on another one");
1084 lwlock_stats *lwstats;
1086 lwstats = get_lwlock_stats_entry(lock);
1088 lwstats->dequeue_self_count++;
1145 while (extraWaits-- > 0)
1174 lwlock_stats *lwstats;
1176 lwstats = get_lwlock_stats_entry(lock);
1186 lwstats->ex_acquire_count++;
1188 lwstats->sh_acquire_count++;
1237 LOG_LWDEBUG(
"LWLockAcquire", lock,
"immediately acquired lock");
1261 LOG_LWDEBUG(
"LWLockAcquire", lock,
"acquired, undoing queue");
1278 lwstats->block_count++;
1282 if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
1283 TRACE_POSTGRESQL_LWLOCK_WAIT_START(
T_NAME(lock),
mode);
1305 if (TRACE_POSTGRESQL_LWLOCK_WAIT_DONE_ENABLED())
1306 TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(
T_NAME(lock),
mode);
1315 if (TRACE_POSTGRESQL_LWLOCK_ACQUIRE_ENABLED())
1316 TRACE_POSTGRESQL_LWLOCK_ACQUIRE(
T_NAME(lock),
mode);
1325 while (extraWaits-- > 0)
1366 LOG_LWDEBUG(
"LWLockConditionalAcquire", lock,
"failed");
1367 if (TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_FAIL_ENABLED())
1368 TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_FAIL(
T_NAME(lock),
mode);
1375 if (TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE_ENABLED())
1376 TRACE_POSTGRESQL_LWLOCK_CONDACQUIRE(
T_NAME(lock),
mode);
1402 lwlock_stats *lwstats;
1404 lwstats = get_lwlock_stats_entry(lock);
1440 LOG_LWDEBUG(
"LWLockAcquireOrWait", lock,
"waiting");
1443 lwstats->block_count++;
1447 if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
1448 TRACE_POSTGRESQL_LWLOCK_WAIT_START(
T_NAME(lock),
mode);
1466 if (TRACE_POSTGRESQL_LWLOCK_WAIT_DONE_ENABLED())
1467 TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(
T_NAME(lock),
mode);
1470 LOG_LWDEBUG(
"LWLockAcquireOrWait", lock,
"awakened");
1474 LOG_LWDEBUG(
"LWLockAcquireOrWait", lock,
"acquired, undoing queue");
1489 while (extraWaits-- > 0)
1496 LOG_LWDEBUG(
"LWLockAcquireOrWait", lock,
"failed");
1497 if (TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_FAIL_ENABLED())
1498 TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_FAIL(
T_NAME(lock),
mode);
1502 LOG_LWDEBUG(
"LWLockAcquireOrWait", lock,
"succeeded");
1506 if (TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT_ENABLED())
1507 TRACE_POSTGRESQL_LWLOCK_ACQUIRE_OR_WAIT(
T_NAME(lock),
mode);
1553 if (
value != oldval)
1589 bool result =
false;
1591 lwlock_stats *lwstats;
1593 lwstats = get_lwlock_stats_entry(lock);
1644 LOG_LWDEBUG(
"LWLockWaitForVar", lock,
"free, undoing queue");
1661 lwstats->block_count++;
1665 if (TRACE_POSTGRESQL_LWLOCK_WAIT_START_ENABLED())
1685 if (TRACE_POSTGRESQL_LWLOCK_WAIT_DONE_ENABLED())
1689 LOG_LWDEBUG(
"LWLockWaitForVar", lock,
"awakened");
1697 while (extraWaits-- > 0)
1819 if (TRACE_POSTGRESQL_LWLOCK_RELEASE_ENABLED())
1820 TRACE_POSTGRESQL_LWLOCK_RELEASE(
T_NAME(lock));
1829 check_waiters =
true;
1831 check_waiters =
false;
1840 LOG_LWDEBUG(
"LWLockRelease", lock,
"releasing waiters");
1913 char *held_lock_addr;
1918 begin = (
char *) lock;
1919 end = begin + nlocks * stride;
1923 if (held_lock_addr >= begin &&
1924 held_lock_addr < end &&
1925 (held_lock_addr - begin) % stride == 0)
static uint32 pg_atomic_fetch_and_u32(volatile pg_atomic_uint32 *ptr, uint32 and_)
static bool pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
static uint32 pg_atomic_fetch_or_u32(volatile pg_atomic_uint32 *ptr, uint32 or_)
static uint32 pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
static uint32 pg_atomic_fetch_sub_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
static void pg_atomic_init_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
#define pg_write_barrier()
static uint32 pg_atomic_fetch_add_u32(volatile pg_atomic_uint32 *ptr, int32 add_)
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
static uint64 pg_atomic_exchange_u64(volatile pg_atomic_uint64 *ptr, uint64 newval)
#define PG_USED_FOR_ASSERTS_ONLY
#define Assert(condition)
#define MemSet(start, val, len)
#define fprintf(file, fmt, msg)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
void * hash_seq_search(HASH_SEQ_STATUS *status)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
int errmsg_internal(const char *fmt,...)
int errhidestmt(bool hide_stmt)
int errhidecontext(bool hide_ctx)
#define ereport(elevel,...)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
void LWLockUpdateVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val)
StaticAssertDecl(LW_VAL_EXCLUSIVE >(uint32) MAX_BACKENDS, "MAX_BACKENDS too big for lwlock.c")
static void LWLockWakeup(LWLock *lock)
bool LWLockHeldByMe(LWLock *lock)
static LWLockHandle held_lwlocks[MAX_SIMUL_LWLOCKS]
static int LWLockTrancheNamesAllocated
void LWLockReleaseClearVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 val)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
NamedLWLockTranche * NamedLWLockTrancheArray
static bool LWLockAttemptLock(LWLock *lock, LWLockMode mode)
static void LWLockWaitListLock(LWLock *lock)
void LWLockRegisterTranche(int tranche_id, const char *tranche_name)
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
static void LWLockReportWaitEnd(void)
struct LWLockHandle LWLockHandle
bool LWLockWaitForVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval, uint64 *newval)
int LWLockNewTrancheId(void)
static const char * GetLWTrancheName(uint16 trancheId)
int NamedLWLockTrancheRequests
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
#define LW_FLAG_RELEASE_OK
#define LW_FLAG_HAS_WAITERS
#define MAX_SIMUL_LWLOCKS
struct NamedLWLockTrancheRequest NamedLWLockTrancheRequest
static int NumLWLocksForNamedTranches(void)
void LWLockRelease(LWLock *lock)
static int num_held_lwlocks
void LWLockReleaseAll(void)
static void InitializeLWLocks(void)
void LWLockInitialize(LWLock *lock, int tranche_id)
static int NamedLWLockTrancheRequestsAllocated
static const char *const BuiltinTrancheNames[]
static NamedLWLockTrancheRequest * NamedLWLockTrancheRequestArray
static void LWLockWaitListUnlock(LWLock *lock)
static const char ** LWLockTrancheNames
#define LOG_LWDEBUG(a, b, c)
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
bool LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
static void LWLockQueueSelf(LWLock *lock, LWLockMode mode)
#define PRINT_LWDEBUG(a, b, c)
static void LWLockReportWaitStart(LWLock *lock)
LWLockPadded * MainLWLockArray
const char * GetLWLockIdentifier(uint32 classId, uint16 eventId)
static void LWLockDequeueSelf(LWLock *lock)
Size LWLockShmemSize(void)
bool LWLockAnyHeldByMe(LWLock *lock, int nlocks, size_t stride)
static bool LWLockConflictsWithVar(LWLock *lock, pg_atomic_uint64 *valptr, uint64 oldval, uint64 *newval, bool *result)
void InitLWLockAccess(void)
#define LWLOCK_PADDED_SIZE
#define BUFFER_MAPPING_LWLOCK_OFFSET
#define NUM_LOCK_PARTITIONS
@ LWTRANCHE_FIRST_USER_DEFINED
@ LWTRANCHE_SHARED_TIDBITMAP
@ LWTRANCHE_PER_SESSION_DSA
@ LWTRANCHE_PARALLEL_QUERY_DSA
@ LWTRANCHE_COMMITTS_BUFFER
@ LWTRANCHE_PARALLEL_VACUUM_DSA
@ LWTRANCHE_SUBTRANS_BUFFER
@ LWTRANCHE_PER_SESSION_RECORD_TYPMOD
@ LWTRANCHE_LAUNCHER_HASH
@ LWTRANCHE_DSM_REGISTRY_DSA
@ LWTRANCHE_DSM_REGISTRY_HASH
@ LWTRANCHE_REPLICATION_ORIGIN_STATE
@ LWTRANCHE_MULTIXACTOFFSET_SLRU
@ LWTRANCHE_PARALLEL_APPEND
@ LWTRANCHE_REPLICATION_SLOT_IO
@ LWTRANCHE_SUBTRANS_SLRU
@ LWTRANCHE_MULTIXACTMEMBER_SLRU
@ LWTRANCHE_BUFFER_CONTENT
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
@ LWTRANCHE_NOTIFY_BUFFER
@ LWTRANCHE_PER_SESSION_RECORD_TYPE
@ LWTRANCHE_PREDICATE_LOCK_MANAGER
@ LWTRANCHE_BUFFER_MAPPING
@ LWTRANCHE_SERIAL_BUFFER
@ LWTRANCHE_PARALLEL_HASH_JOIN
@ LWTRANCHE_COMMITTS_SLRU
@ LWTRANCHE_PER_XACT_PREDICATE_LIST
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
@ LWTRANCHE_SHARED_TUPLESTORE
@ LWTRANCHE_LOCK_FASTPATH
#define LOCK_MANAGER_LWLOCK_OFFSET
#define NUM_BUFFER_PARTITIONS
#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET
#define NUM_FIXED_LWLOCKS
#define NUM_PREDICATELOCK_PARTITIONS
void * MemoryContextAlloc(MemoryContext context, Size size)
void * MemoryContextAllocZero(MemoryContext context, Size size)
void * repalloc(void *pointer, Size size)
MemoryContext TopMemoryContext
void MemoryContextDelete(MemoryContext context)
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define RESUME_INTERRUPTS()
#define HOLD_INTERRUPTS()
bool process_shmem_requests_in_progress
#define repalloc0_array(pointer, type, oldcount, count)
static uint32 pg_nextpower2_32(uint32 num)
static PgChecksumMode mode
size_t strlcpy(char *dst, const char *src, size_t siz)
void PGSemaphoreUnlock(PGSemaphore sema)
void PGSemaphoreLock(PGSemaphore sema)
#define GetPGProcByNumber(n)
#define proclist_delete(list, procno, link_member)
static void proclist_init(proclist_head *list)
#define proclist_push_tail(list, procno, link_member)
#define proclist_push_head(list, procno, link_member)
#define proclist_foreach_modify(iter, lhead, link_member)
static bool proclist_is_empty(const proclist_head *list)
void perform_spin_delay(SpinDelayStatus *status)
void finish_spin_delay(SpinDelayStatus *status)
#define init_local_spin_delay(status)
Size add_size(Size s1, Size s2)
Size mul_size(Size s1, Size s2)
void * ShmemAlloc(Size size)
static pg_noinline void Size size
#define SpinLockRelease(lock)
#define SpinLockAcquire(lock)
char tranche_name[NAMEDATALEN]
static void pgstat_report_wait_start(uint32 wait_event_info)
static void pgstat_report_wait_end(void)
static TimestampTz wakeup[NUM_WALRCV_WAKEUPS]