kernel/locking/qspinlock_paravirt.h
Source file repositories/reference/linux-study-clean/kernel/locking/qspinlock_paravirt.h
File Facts
- System
- Linux kernel
- Corpus path
kernel/locking/qspinlock_paravirt.h- Extension
.h- Size
- 16405 bytes
- Lines
- 558
- Domain
- Core OS
- Bucket
- Scheduler, Processes, Timers, Sync, And Syscalls
- Inferred role
- Core OS: implementation source
- Status
- source implementation candidate
Why This File Exists
Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/hash.hlinux/memblock.hlinux/debug_locks.hasm/qspinlock_paravirt.h
Detected Declarations
struct pv_nodestruct pv_hash_entryenum vcpu_statefunction queued_spin_trylockfunction set_pendingfunction pv_queued_spin_steal_lockfunction set_pendingfunction trylock_clear_pendingfunction __pv_init_lock_hashfunction for_each_hash_entryfunction for_each_hash_entryfunction pv_wait_earlyfunction pv_init_nodefunction pv_kick_nodefunction pv_wait_nodefunction __pv_queued_spin_unlockfunction __pv_queued_spin_unlockfunction __pv_queued_spin_unlockfunction __pv_queued_spin_unlock
Annotated Snippet
struct pv_node {
struct mcs_spinlock mcs;
int cpu;
u8 state;
};
/*
* Hybrid PV queued/unfair lock
*
* By replacing the regular queued_spin_trylock() with the function below,
* it will be called once when a lock waiter enter the PV slowpath before
* being queued.
*
* The pending bit is set by the queue head vCPU of the MCS wait queue in
* pv_wait_head_or_lock() to signal that it is ready to spin on the lock.
* When that bit becomes visible to the incoming waiters, no lock stealing
* is allowed. The function will return immediately to make the waiters
* enter the MCS wait queue. So lock starvation shouldn't happen as long
* as the queued mode vCPUs are actively running to set the pending bit
* and hence disabling lock stealing.
*
* When the pending bit isn't set, the lock waiters will stay in the unfair
* mode spinning on the lock unless the MCS wait queue is empty. In this
* case, the lock waiters will enter the queued mode slowpath trying to
* become the queue head and set the pending bit.
*
* This hybrid PV queued/unfair lock combines the best attributes of a
* queued lock (no lock starvation) and an unfair lock (good performance
* on not heavily contended locks).
*/
#define queued_spin_trylock(l) pv_hybrid_queued_unfair_trylock(l)
static inline bool pv_hybrid_queued_unfair_trylock(struct qspinlock *lock)
{
/*
* Stay in unfair lock mode as long as queued mode waiters are
* present in the MCS wait queue but the pending bit isn't set.
*/
for (;;) {
int val = atomic_read(&lock->val);
u8 old = 0;
if (!(val & _Q_LOCKED_PENDING_MASK) &&
try_cmpxchg_acquire(&lock->locked, &old, _Q_LOCKED_VAL)) {
lockevent_inc(pv_lock_stealing);
return true;
}
if (!(val & _Q_TAIL_MASK) || (val & _Q_PENDING_MASK))
break;
cpu_relax();
}
return false;
}
/*
* The pending bit is used by the queue head vCPU to indicate that it
* is actively spinning on the lock and no lock stealing is allowed.
*/
#if _Q_PENDING_BITS == 8
static __always_inline void set_pending(struct qspinlock *lock)
{
WRITE_ONCE(lock->pending, 1);
}
/*
* The pending bit check in pv_queued_spin_steal_lock() isn't a memory
* barrier. Therefore, an atomic cmpxchg_acquire() is used to acquire the
* lock just to be sure that it will get it.
*/
static __always_inline bool trylock_clear_pending(struct qspinlock *lock)
{
u16 old = _Q_PENDING_VAL;
return !READ_ONCE(lock->locked) &&
try_cmpxchg_acquire(&lock->locked_pending, &old, _Q_LOCKED_VAL);
}
#else /* _Q_PENDING_BITS == 8 */
static __always_inline void set_pending(struct qspinlock *lock)
{
atomic_or(_Q_PENDING_VAL, &lock->val);
}
static __always_inline bool trylock_clear_pending(struct qspinlock *lock)
{
int old, new;
old = atomic_read(&lock->val);
do {
if (old & _Q_LOCKED_MASK)
Annotation
- Immediate include surface: `linux/hash.h`, `linux/memblock.h`, `linux/debug_locks.h`, `asm/qspinlock_paravirt.h`.
- Detected declarations: `struct pv_node`, `struct pv_hash_entry`, `enum vcpu_state`, `function queued_spin_trylock`, `function set_pending`, `function pv_queued_spin_steal_lock`, `function set_pending`, `function trylock_clear_pending`, `function __pv_init_lock_hash`, `function for_each_hash_entry`.
- Atlas domain: Core OS / Scheduler, Processes, Timers, Sync, And Syscalls.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.