summaryrefslogtreecommitdiff
path: root/include/linux/rwsem.h
blob: e516c81daf39168f2cd34fedd425e0561559ceb8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* rwsem.h: R/W semaphores, public interface
 *
 * Written by David Howells (dhowells@redhat.com).
 * Derived from asm-i386/semaphore.h
 */

#ifndef _LINUX_RWSEM_H
#define _LINUX_RWSEM_H

#include <linux/linkage.h>

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/rt_lock.h>
#include <asm/system.h>
#include <asm/atomic.h>

struct rw_anon_semaphore;
struct rw_semaphore;

#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK
#include <linux/rwsem-spinlock.h> /* use a generic implementation */
#else
#include <asm/rwsem.h> /* use an arch-specific implementation */
#endif

/*
 * lock for reading
 */
extern void anon_down_read(struct rw_anon_semaphore *sem);

/*
 * trylock for reading -- returns 1 if successful, 0 if contention
 */
extern int anon_down_read_trylock(struct rw_anon_semaphore *sem);

/*
 * lock for writing
 */
extern void anon_down_write(struct rw_anon_semaphore *sem);

/*
 * trylock for writing -- returns 1 if successful, 0 if contention
 */
extern int anon_down_write_trylock(struct rw_anon_semaphore *sem);

/*
 * release a read lock
 */
extern void anon_up_read(struct rw_anon_semaphore *sem);

/*
 * release a write lock
 */
extern void anon_up_write(struct rw_anon_semaphore *sem);

/*
 * downgrade write lock to read lock
 */
extern void anon_downgrade_write(struct rw_anon_semaphore *sem);

#ifdef CONFIG_DEBUG_LOCK_ALLOC
/*
 * nested locking. NOTE: rwsems are not allowed to recurse
 * (which occurs if the same task tries to acquire the same
 * lock instance multiple times), but multiple locks of the
 * same lock class might be taken, if the order of the locks
 * is always the same. This ordering rule can be expressed
 * to lockdep via the _nested() APIs, but enumerating the
 * subclasses that are used. (If the nesting relationship is
 * static then another method for expressing nested locking is
 * the explicit definition of lock class keys and the use of
 * lockdep_set_class() at lock initialization time.
 * See Documentation/lockdep-design.txt for more details.)
 */
extern void anon_down_read_nested(struct rw_anon_semaphore *sem, int subclass);
extern void anon_down_write_nested(struct rw_anon_semaphore *sem, int subclass);
/*
 * Take/release a lock when not the owner will release it.
 *
 * [ This API should be avoided as much as possible - the
 *   proper abstraction for this case is completions. ]
 */
extern void anon_down_read_non_owner(struct rw_anon_semaphore *sem);
extern void anon_up_read_non_owner(struct rw_anon_semaphore *sem);
#else
# define anon_down_read_nested(sem, subclass)	anon_down_read(sem)
# define anon_down_write_nested(sem, subclass)	anon_down_write(sem)
# define anon_down_read_non_owner(sem)		anon_down_read(sem)
# define anon_up_read_non_owner(sem)		anon_up_read(sem)
#endif

#ifdef CONFIG_PREEMPT_RT

#include <linux/rt_lock.h>

#define init_rwsem(sem)		rt_init_rwsem(sem)
#define rwsem_is_locked(s)	rt_mutex_is_locked(&(s)->lock)

static inline void down_read(struct rw_semaphore *sem)
{
	rt_down_read(sem);
}

static inline int down_read_trylock(struct rw_semaphore *sem)
{
	return rt_down_read_trylock(sem);
}

static inline void down_write(struct rw_semaphore *sem)
{
	rt_down_write(sem);
}

static inline int down_write_trylock(struct rw_semaphore *sem)
{
	return rt_down_write_trylock(sem);
}

static inline void up_read(struct rw_semaphore *sem)
{
	rt_up_read(sem);
}

static inline void up_write(struct rw_semaphore *sem)
{
	rt_up_write(sem);
}

static inline void downgrade_write(struct rw_semaphore *sem)
{
	rt_downgrade_write(sem);
}

static inline void down_read_nested(struct rw_semaphore *sem, int subclass)
{
	return rt_down_read_nested(sem, subclass);
}

static inline void down_write_nested(struct rw_semaphore *sem, int subclass)
{
	rt_down_write_nested(sem, subclass);
}

#else
/*
 * Non preempt-rt implementations
 */
static inline void down_read(struct rw_semaphore *sem)
{
	anon_down_read((struct rw_anon_semaphore *)sem);
}

static inline int down_read_trylock(struct rw_semaphore *sem)
{
	return anon_down_read_trylock((struct rw_anon_semaphore *)sem);
}

static inline void down_write(struct rw_semaphore *sem)
{
	anon_down_write((struct rw_anon_semaphore *)sem);
}

static inline int down_write_trylock(struct rw_semaphore *sem)
{
	return anon_down_write_trylock((struct rw_anon_semaphore *)sem);
}

static inline void up_read(struct rw_semaphore *sem)
{
	anon_up_read((struct rw_anon_semaphore *)sem);
}

static inline void up_write(struct rw_semaphore *sem)
{
	anon_up_write((struct rw_anon_semaphore *)sem);
}

static inline void downgrade_write(struct rw_semaphore *sem)
{
	anon_downgrade_write((struct rw_anon_semaphore *)sem);
}

static inline void down_read_nested(struct rw_semaphore *sem, int subclass)
{
	return anon_down_read_nested((struct rw_anon_semaphore *)sem, subclass);
}

static inline void down_write_nested(struct rw_semaphore *sem, int subclass)
{
	anon_down_write_nested((struct rw_anon_semaphore *)sem, subclass);
}
#endif

#endif /* _LINUX_RWSEM_H */