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