blob: 42f806de49d421092a7bd077c8efb4df9546cb94 [file] [log] [blame]
Ingo Molnarc4e05112006-07-03 00:24:29 -07001/* 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>
Livio Soaresc7af77b2007-12-18 15:21:13 +01009#include <linux/sched.h>
Paul Gortmaker9984de12011-05-23 14:51:41 -040010#include <linux/export.h>
Ingo Molnarc4e05112006-07-03 00:24:29 -070011#include <linux/rwsem.h>
12
Arun Sharma600634972011-07-26 16:09:06 -070013#include <linux/atomic.h>
Ingo Molnarc4e05112006-07-03 00:24:29 -070014
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -070015#if defined(CONFIG_SMP) && defined(CONFIG_RWSEM_XCHGADD_ALGORITHM)
16static inline void rwsem_set_owner(struct rw_semaphore *sem)
17{
18 sem->owner = current;
19}
20
21static inline void rwsem_clear_owner(struct rw_semaphore *sem)
22{
23 sem->owner = NULL;
24}
25
26#else
27static inline void rwsem_set_owner(struct rw_semaphore *sem)
28{
29}
30
31static inline void rwsem_clear_owner(struct rw_semaphore *sem)
32{
33}
34#endif
35
Ingo Molnarc4e05112006-07-03 00:24:29 -070036/*
37 * lock for reading
38 */
Livio Soaresc7af77b2007-12-18 15:21:13 +010039void __sched down_read(struct rw_semaphore *sem)
Ingo Molnarc4e05112006-07-03 00:24:29 -070040{
41 might_sleep();
42 rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
43
Peter Zijlstra4fe87742007-07-19 01:48:58 -070044 LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
Ingo Molnarc4e05112006-07-03 00:24:29 -070045}
46
47EXPORT_SYMBOL(down_read);
48
49/*
50 * trylock for reading -- returns 1 if successful, 0 if contention
51 */
52int down_read_trylock(struct rw_semaphore *sem)
53{
54 int ret = __down_read_trylock(sem);
55
56 if (ret == 1)
57 rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
58 return ret;
59}
60
61EXPORT_SYMBOL(down_read_trylock);
62
63/*
64 * lock for writing
65 */
Livio Soaresc7af77b2007-12-18 15:21:13 +010066void __sched down_write(struct rw_semaphore *sem)
Ingo Molnarc4e05112006-07-03 00:24:29 -070067{
68 might_sleep();
69 rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
70
Peter Zijlstra4fe87742007-07-19 01:48:58 -070071 LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -070072 rwsem_set_owner(sem);
Ingo Molnarc4e05112006-07-03 00:24:29 -070073}
74
75EXPORT_SYMBOL(down_write);
76
77/*
78 * trylock for writing -- returns 1 if successful, 0 if contention
79 */
80int down_write_trylock(struct rw_semaphore *sem)
81{
82 int ret = __down_write_trylock(sem);
83
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -070084 if (ret == 1) {
Pavel Emelianov428e6ce2007-05-08 00:29:10 -070085 rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -070086 rwsem_set_owner(sem);
87 }
88
Ingo Molnarc4e05112006-07-03 00:24:29 -070089 return ret;
90}
91
92EXPORT_SYMBOL(down_write_trylock);
93
94/*
95 * release a read lock
96 */
97void up_read(struct rw_semaphore *sem)
98{
99 rwsem_release(&sem->dep_map, 1, _RET_IP_);
100
101 __up_read(sem);
102}
103
104EXPORT_SYMBOL(up_read);
105
106/*
107 * release a write lock
108 */
109void up_write(struct rw_semaphore *sem)
110{
111 rwsem_release(&sem->dep_map, 1, _RET_IP_);
112
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -0700113 rwsem_clear_owner(sem);
Ingo Molnarc4e05112006-07-03 00:24:29 -0700114 __up_write(sem);
115}
116
117EXPORT_SYMBOL(up_write);
118
119/*
120 * downgrade write lock to read lock
121 */
122void downgrade_write(struct rw_semaphore *sem)
123{
124 /*
125 * lockdep: a downgraded write will live on as a write
126 * dependency.
127 */
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -0700128 rwsem_clear_owner(sem);
Ingo Molnarc4e05112006-07-03 00:24:29 -0700129 __downgrade_write(sem);
130}
131
132EXPORT_SYMBOL(downgrade_write);
Ingo Molnar4ea21762006-07-03 00:24:53 -0700133
134#ifdef CONFIG_DEBUG_LOCK_ALLOC
135
136void down_read_nested(struct rw_semaphore *sem, int subclass)
137{
138 might_sleep();
139 rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
140
Peter Zijlstra4fe87742007-07-19 01:48:58 -0700141 LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
Ingo Molnar4ea21762006-07-03 00:24:53 -0700142}
143
144EXPORT_SYMBOL(down_read_nested);
145
Jiri Kosina1b963c82013-01-11 14:31:56 -0800146void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
147{
148 might_sleep();
149 rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_);
150
151 LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -0700152 rwsem_set_owner(sem);
Jiri Kosina1b963c82013-01-11 14:31:56 -0800153}
154
155EXPORT_SYMBOL(_down_write_nest_lock);
156
Kent Overstreet84759c62011-09-21 21:43:05 -0700157void down_read_non_owner(struct rw_semaphore *sem)
158{
159 might_sleep();
160
161 __down_read(sem);
162}
163
164EXPORT_SYMBOL(down_read_non_owner);
165
Ingo Molnar4ea21762006-07-03 00:24:53 -0700166void down_write_nested(struct rw_semaphore *sem, int subclass)
167{
168 might_sleep();
169 rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
170
Peter Zijlstra4fe87742007-07-19 01:48:58 -0700171 LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
Davidlohr Bueso4fc828e2014-05-02 11:24:15 -0700172 rwsem_set_owner(sem);
Ingo Molnar4ea21762006-07-03 00:24:53 -0700173}
174
175EXPORT_SYMBOL(down_write_nested);
176
Kent Overstreet84759c62011-09-21 21:43:05 -0700177void up_read_non_owner(struct rw_semaphore *sem)
178{
179 __up_read(sem);
180}
181
182EXPORT_SYMBOL(up_read_non_owner);
183
Ingo Molnar4ea21762006-07-03 00:24:53 -0700184#endif
185
186