This interface is an implementation of sleeping reader-writer exclusion, which serves as an alternative for spinning ones. Reader-writer semaphores are represented by struct rw_semaphore, declared in the kernel header <linux/rwsem.h>:
struct rw_semaphore { atomic_long_t count; struct list_head wait_list; raw_spinlock_t wait_lock; #ifdef CONFIG_RWSEM_SPIN_ON_OWNER struct optimistic_spin_queue osq; /* spinner MCS lock */ /* * Write owner. Used as a speculative check to see * if the owner is running on the cpu. */ struct task_struct *owner; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif };
This structure is identical to that of a mutex, and is designed to support optimistic spinning with osq; it also includes debug support through the kernel's lockdep. Count serves as an exclusion counter, which is set to 1, allowing a maximum of one writer to own the lock at a point in time. This works since mutual exclusion is only enforced between contending writers, and any number of readers can concurrently share the read lock. wait_lock is a spinlock which protects the semaphore wait_list.
An rw_semaphore can be instantiated and initialized statically through DECLARE_RWSEM(name), and alternatively, it can be dynamically initialized through init_rwsem(sem).
As with the case of rw-spinlocks, this interface too offers distinct routines for lock acquisition in reader and writer paths. Following is a list of interface operations:
/* reader interfaces */
void down_read(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem); /* trylock for reading -- returns 1 if successful, 0 if contention */ int down_read_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);
/* writer Interfaces */
void down_write(struct rw_semaphore *sem);
int __must_check down_write_killable(struct rw_semaphore *sem);
/* trylock for writing -- returns 1 if successful, 0 if contention */
int down_write_trylock(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem); /* downgrade write lock to read lock */
void downgrade_write(struct rw_semaphore *sem);
/* check if rw-sem is currently locked */
int rwsem_is_locked(struct rw_semaphore *sem);
These operations are implemented in the source file <kernel/locking/rwsem.c>; the code is quite self explanatory and we will not discuss it any further.