1
2
3
4
5
6
7#ifndef _LINUX_RWSEM_H
8#define _LINUX_RWSEM_H
9
10#include <linux/linkage.h>
11
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/list.h>
15#include <linux/spinlock.h>
16#include <linux/atomic.h>
17#include <linux/err.h>
18#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
19#include <linux/osq_lock.h>
20#endif
21
22struct rw_semaphore;
23
24#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
25#include <linux/rwsem-spinlock.h>
26#define __RWSEM_INIT_COUNT(name) .count = RWSEM_UNLOCKED_VALUE
27#else
28
29#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
30struct slist_head {
31 struct list_head *next;
32};
33
34
35
36
37static inline bool slist_empty(struct slist_head *head)
38{
39 return READ_ONCE(head->next) == (void *)head;
40}
41
42#define SLIST_HEAD_INIT(name) { (void *)&(name) }
43#else
44#define SLIST_HEAD_INIT(name) LIST_HEAD_INIT(name)
45#define slist_empty(name) list_empty(name)
46#endif
47
48
49struct rw_semaphore {
50 RH_KABI_REPLACE(long count,
51 atomic_long_t count)
52 raw_spinlock_t wait_lock;
53#if defined(CONFIG_RWSEM_SPIN_ON_OWNER) && !defined(__GENKSYMS__)
54 struct optimistic_spin_queue osq;
55 struct slist_head wait_list;
56
57
58
59
60 struct task_struct *owner;
61#else
62 struct list_head wait_list;
63#endif
64#ifdef CONFIG_DEBUG_LOCK_ALLOC
65 struct lockdep_map dep_map;
66#endif
67};
68
69extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
70extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
71extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
72extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
73
74
75#include <asm/rwsem.h>
76
77
78static inline int rwsem_is_locked(struct rw_semaphore *sem)
79{
80 return atomic_long_read(&sem->count) != 0;
81}
82
83#define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)
84#endif
85
86
87
88#ifdef CONFIG_DEBUG_LOCK_ALLOC
89# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
90#else
91# define __RWSEM_DEP_MAP_INIT(lockname)
92#endif
93
94#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
95#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, \
96 .owner = (void *)&(lockname).wait_list
97#else
98#define __RWSEM_OPT_INIT(lockname)
99#endif
100
101#define __RWSEM_INITIALIZER(name) \
102 { __RWSEM_INIT_COUNT(name), \
103 .wait_list = SLIST_HEAD_INIT((name).wait_list), \
104 .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \
105 __RWSEM_OPT_INIT(name) \
106 __RWSEM_DEP_MAP_INIT(name) }
107
108#define DECLARE_RWSEM(name) \
109 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
110
111extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
112 struct lock_class_key *key);
113
114#define init_rwsem(sem) \
115do { \
116 static struct lock_class_key __key; \
117 \
118 __init_rwsem((sem), #sem, &__key); \
119} while (0)
120
121
122
123
124
125
126
127static inline int rwsem_is_contended(struct rw_semaphore *sem)
128{
129 return !slist_empty(&sem->wait_list);
130}
131
132
133
134
135extern void down_read(struct rw_semaphore *sem);
136
137
138
139
140extern int down_read_trylock(struct rw_semaphore *sem);
141
142
143
144
145extern void down_write(struct rw_semaphore *sem);
146
147
148
149
150extern int down_write_trylock(struct rw_semaphore *sem);
151
152
153
154
155extern void up_read(struct rw_semaphore *sem);
156
157
158
159
160extern void up_write(struct rw_semaphore *sem);
161
162
163
164
165extern void downgrade_write(struct rw_semaphore *sem);
166
167#ifdef CONFIG_DEBUG_LOCK_ALLOC
168
169
170
171
172
173
174
175
176
177
178
179
180
181extern void down_read_nested(struct rw_semaphore *sem, int subclass);
182extern void down_write_nested(struct rw_semaphore *sem, int subclass);
183extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest_lock);
184
185# define down_write_nest_lock(sem, nest_lock) \
186do { \
187 typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \
188 _down_write_nest_lock(sem, &(nest_lock)->dep_map); \
189} while (0);
190
191
192
193
194
195
196
197extern void down_read_non_owner(struct rw_semaphore *sem);
198extern void up_read_non_owner(struct rw_semaphore *sem);
199#else
200# define down_read_nested(sem, subclass) down_read(sem)
201# define down_write_nest_lock(sem, nest_lock) down_write(sem)
202# define down_write_nested(sem, subclass) down_write(sem)
203# define down_read_non_owner(sem) down_read(sem)
204# define up_read_non_owner(sem) up_read(sem)
205#endif
206
207#endif
208