kernel/locking/percpu-rwsem.c
Source file repositories/reference/linux-study-clean/kernel/locking/percpu-rwsem.c
File Facts
- System
- Linux kernel
- Corpus path
kernel/locking/percpu-rwsem.c- Extension
.c- Size
- 8782 bytes
- Lines
- 320
- Domain
- Core OS
- Bucket
- Scheduler, Processes, Timers, Sync, And Syscalls
- Inferred role
- Core OS: exported/initcall integration point
- Status
- integration 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.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/atomic.hlinux/percpu.hlinux/wait.hlinux/lockdep.hlinux/percpu-rwsem.hlinux/rcupdate.hlinux/sched.hlinux/sched/task.hlinux/sched/debug.hlinux/errno.htrace/events/lock.h
Detected Declarations
function __percpu_init_rwsemfunction percpu_free_rwsemfunction __percpu_down_read_trylockfunction __percpu_down_write_trylockfunction __percpu_rwsem_trylockfunction percpu_rwsem_wake_functionfunction percpu_rwsem_waitfunction __percpu_down_readfunction percpu_is_read_lockedfunction readers_active_checkfunction percpu_down_writefunction percpu_up_writefunction __percpu_up_readexport __percpu_init_rwsemexport percpu_free_rwsemexport __percpu_down_readexport percpu_is_read_lockedexport percpu_down_writeexport percpu_up_writeexport __percpu_up_read
Annotated Snippet
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/atomic.h>
#include <linux/percpu.h>
#include <linux/wait.h>
#include <linux/lockdep.h>
#include <linux/percpu-rwsem.h>
#include <linux/rcupdate.h>
#include <linux/sched.h>
#include <linux/sched/task.h>
#include <linux/sched/debug.h>
#include <linux/errno.h>
#include <trace/events/lock.h>
int __percpu_init_rwsem(struct percpu_rw_semaphore *sem,
const char *name, struct lock_class_key *key)
{
sem->read_count = alloc_percpu(int);
if (unlikely(!sem->read_count))
return -ENOMEM;
rcu_sync_init(&sem->rss);
rcuwait_init(&sem->writer);
init_waitqueue_head(&sem->waiters);
atomic_set(&sem->block, 0);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
lockdep_init_map(&sem->dep_map, name, key, 0);
#endif
return 0;
}
EXPORT_SYMBOL_GPL(__percpu_init_rwsem);
void percpu_free_rwsem(struct percpu_rw_semaphore *sem)
{
/*
* XXX: temporary kludge. The error path in alloc_super()
* assumes that percpu_free_rwsem() is safe after kzalloc().
*/
if (!sem->read_count)
return;
rcu_sync_dtor(&sem->rss);
free_percpu(sem->read_count);
sem->read_count = NULL; /* catch use after free bugs */
}
EXPORT_SYMBOL_GPL(percpu_free_rwsem);
static bool __percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
{
this_cpu_inc(*sem->read_count);
/*
* Due to having preemption disabled the decrement happens on
* the same CPU as the increment, avoiding the
* increment-on-one-CPU-and-decrement-on-another problem.
*
* If the reader misses the writer's assignment of sem->block, then the
* writer is guaranteed to see the reader's increment.
*
* Conversely, any readers that increment their sem->read_count after
* the writer looks are guaranteed to see the sem->block value, which
* in turn means that they are guaranteed to immediately decrement
* their sem->read_count, so that it doesn't matter that the writer
* missed them.
*/
smp_mb(); /* A matches D */
/*
* If !sem->block the critical section starts here, matched by the
* release in percpu_up_write().
*/
if (likely(!atomic_read_acquire(&sem->block)))
return true;
this_cpu_dec(*sem->read_count);
/* Prod writer to re-evaluate readers_active_check() */
rcuwait_wake_up(&sem->writer);
return false;
}
static inline bool __percpu_down_write_trylock(struct percpu_rw_semaphore *sem)
{
if (atomic_read(&sem->block))
return false;
return atomic_xchg(&sem->block, 1) == 0;
}
Annotation
- Immediate include surface: `linux/atomic.h`, `linux/percpu.h`, `linux/wait.h`, `linux/lockdep.h`, `linux/percpu-rwsem.h`, `linux/rcupdate.h`, `linux/sched.h`, `linux/sched/task.h`.
- Detected declarations: `function __percpu_init_rwsem`, `function percpu_free_rwsem`, `function __percpu_down_read_trylock`, `function __percpu_down_write_trylock`, `function __percpu_rwsem_trylock`, `function percpu_rwsem_wake_function`, `function percpu_rwsem_wait`, `function __percpu_down_read`, `function percpu_is_read_locked`, `function readers_active_check`.
- Atlas domain: Core OS / Scheduler, Processes, Timers, Sync, And Syscalls.
- Implementation status: integration 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.