linux/kernel/locking/rwsem.c
<<
>>
Prefs
   1/* kernel/rwsem.c: R/W semaphores, public implementation
   2 *
   3 * Written by David Howells (dhowells@redhat.com).
   4 * Derived from asm-i386/semaphore.h
   5 */
   6
   7#include <linux/types.h>
   8#include <linux/kernel.h>
   9#include <linux/sched.h>
  10#include <linux/export.h>
  11#include <linux/rwsem.h>
  12#include <linux/atomic.h>
  13
  14#include "rwsem.h"
  15
  16/*
  17 * lock for reading
  18 */
  19void __sched down_read(struct rw_semaphore *sem)
  20{
  21        might_sleep();
  22        rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
  23
  24        LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
  25        rwsem_set_reader_owned(sem);
  26}
  27
  28EXPORT_SYMBOL(down_read);
  29
  30/*
  31 * trylock for reading -- returns 1 if successful, 0 if contention
  32 */
  33int down_read_trylock(struct rw_semaphore *sem)
  34{
  35        int ret = __down_read_trylock(sem);
  36
  37        if (ret == 1) {
  38                rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
  39                rwsem_set_reader_owned(sem);
  40        }
  41        return ret;
  42}
  43
  44EXPORT_SYMBOL(down_read_trylock);
  45
  46/*
  47 * lock for writing
  48 */
  49void __sched down_write(struct rw_semaphore *sem)
  50{
  51        might_sleep();
  52        rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
  53
  54        LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
  55        rwsem_set_owner(sem);
  56}
  57
  58EXPORT_SYMBOL(down_write);
  59
  60/*
  61 * lock for writing
  62 */
  63int __sched down_write_killable(struct rw_semaphore *sem)
  64{
  65        might_sleep();
  66        rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
  67
  68        if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) {
  69                rwsem_release(&sem->dep_map, 1, _RET_IP_);
  70                return -EINTR;
  71        }
  72
  73        rwsem_set_owner(sem);
  74        return 0;
  75}
  76
  77EXPORT_SYMBOL(down_write_killable);
  78
  79/*
  80 * trylock for writing -- returns 1 if successful, 0 if contention
  81 */
  82int down_write_trylock(struct rw_semaphore *sem)
  83{
  84        int ret = __down_write_trylock(sem);
  85
  86        if (ret == 1) {
  87                rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
  88                rwsem_set_owner(sem);
  89        }
  90
  91        return ret;
  92}
  93
  94EXPORT_SYMBOL(down_write_trylock);
  95
  96/*
  97 * release a read lock
  98 */
  99void up_read(struct rw_semaphore *sem)
 100{
 101        rwsem_release(&sem->dep_map, 1, _RET_IP_);
 102
 103        __up_read(sem);
 104}
 105
 106EXPORT_SYMBOL(up_read);
 107
 108/*
 109 * release a write lock
 110 */
 111void up_write(struct rw_semaphore *sem)
 112{
 113        rwsem_release(&sem->dep_map, 1, _RET_IP_);
 114
 115        rwsem_clear_owner(sem);
 116        __up_write(sem);
 117}
 118
 119EXPORT_SYMBOL(up_write);
 120
 121/*
 122 * downgrade write lock to read lock
 123 */
 124void downgrade_write(struct rw_semaphore *sem)
 125{
 126        /*
 127         * lockdep: a downgraded write will live on as a write
 128         * dependency.
 129         */
 130        rwsem_set_reader_owned(sem);
 131        __downgrade_write(sem);
 132}
 133
 134EXPORT_SYMBOL(downgrade_write);
 135
 136#ifdef CONFIG_DEBUG_LOCK_ALLOC
 137
 138void down_read_nested(struct rw_semaphore *sem, int subclass)
 139{
 140        might_sleep();
 141        rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
 142
 143        LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
 144        rwsem_set_reader_owned(sem);
 145}
 146
 147EXPORT_SYMBOL(down_read_nested);
 148
 149void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
 150{
 151        might_sleep();
 152        rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_);
 153
 154        LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
 155        rwsem_set_owner(sem);
 156}
 157
 158EXPORT_SYMBOL(_down_write_nest_lock);
 159
 160void down_read_non_owner(struct rw_semaphore *sem)
 161{
 162        might_sleep();
 163
 164        __down_read(sem);
 165}
 166
 167EXPORT_SYMBOL(down_read_non_owner);
 168
 169void down_write_nested(struct rw_semaphore *sem, int subclass)
 170{
 171        might_sleep();
 172        rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
 173
 174        LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
 175        rwsem_set_owner(sem);
 176}
 177
 178EXPORT_SYMBOL(down_write_nested);
 179
 180int __sched down_write_killable_nested(struct rw_semaphore *sem, int subclass)
 181{
 182        might_sleep();
 183        rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
 184
 185        if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) {
 186                rwsem_release(&sem->dep_map, 1, _RET_IP_);
 187                return -EINTR;
 188        }
 189
 190        rwsem_set_owner(sem);
 191        return 0;
 192}
 193
 194EXPORT_SYMBOL(down_write_killable_nested);
 195
 196void up_read_non_owner(struct rw_semaphore *sem)
 197{
 198        __up_read(sem);
 199}
 200
 201EXPORT_SYMBOL(up_read_non_owner);
 202
 203#endif
 204
 205
 206