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#include <linux/compiler.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/sched.h>
32#include <linux/semaphore.h>
33#include <linux/spinlock.h>
34#include <linux/ftrace.h>
35
36static noinline void __down(struct semaphore *sem);
37static noinline int __down_interruptible(struct semaphore *sem);
38static noinline int __down_killable(struct semaphore *sem);
39static noinline int __down_timeout(struct semaphore *sem, long jiffies);
40static noinline void __up(struct semaphore *sem);
41
42
43
44
45
46
47
48
49
50
51
52
53void down(struct semaphore *sem)
54{
55 unsigned long flags;
56
57 spin_lock_irqsave(&sem->lock, flags);
58 if (likely(sem->count > 0))
59 sem->count--;
60 else
61 __down(sem);
62 spin_unlock_irqrestore(&sem->lock, flags);
63}
64EXPORT_SYMBOL(down);
65
66
67
68
69
70
71
72
73
74
75int down_interruptible(struct semaphore *sem)
76{
77 unsigned long flags;
78 int result = 0;
79
80 spin_lock_irqsave(&sem->lock, flags);
81 if (likely(sem->count > 0))
82 sem->count--;
83 else
84 result = __down_interruptible(sem);
85 spin_unlock_irqrestore(&sem->lock, flags);
86
87 return result;
88}
89EXPORT_SYMBOL(down_interruptible);
90
91
92
93
94
95
96
97
98
99
100
101int down_killable(struct semaphore *sem)
102{
103 unsigned long flags;
104 int result = 0;
105
106 spin_lock_irqsave(&sem->lock, flags);
107 if (likely(sem->count > 0))
108 sem->count--;
109 else
110 result = __down_killable(sem);
111 spin_unlock_irqrestore(&sem->lock, flags);
112
113 return result;
114}
115EXPORT_SYMBOL(down_killable);
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130int down_trylock(struct semaphore *sem)
131{
132 unsigned long flags;
133 int count;
134
135 spin_lock_irqsave(&sem->lock, flags);
136 count = sem->count - 1;
137 if (likely(count >= 0))
138 sem->count = count;
139 spin_unlock_irqrestore(&sem->lock, flags);
140
141 return (count < 0);
142}
143EXPORT_SYMBOL(down_trylock);
144
145
146
147
148
149
150
151
152
153
154
155int down_timeout(struct semaphore *sem, long jiffies)
156{
157 unsigned long flags;
158 int result = 0;
159
160 spin_lock_irqsave(&sem->lock, flags);
161 if (likely(sem->count > 0))
162 sem->count--;
163 else
164 result = __down_timeout(sem, jiffies);
165 spin_unlock_irqrestore(&sem->lock, flags);
166
167 return result;
168}
169EXPORT_SYMBOL(down_timeout);
170
171
172
173
174
175
176
177
178void up(struct semaphore *sem)
179{
180 unsigned long flags;
181
182 spin_lock_irqsave(&sem->lock, flags);
183 if (likely(list_empty(&sem->wait_list)))
184 sem->count++;
185 else
186 __up(sem);
187 spin_unlock_irqrestore(&sem->lock, flags);
188}
189EXPORT_SYMBOL(up);
190
191
192
193struct semaphore_waiter {
194 struct list_head list;
195 struct task_struct *task;
196 int up;
197};
198
199
200
201
202
203
204static inline int __sched __down_common(struct semaphore *sem, long state,
205 long timeout)
206{
207 struct task_struct *task = current;
208 struct semaphore_waiter waiter;
209
210 list_add_tail(&waiter.list, &sem->wait_list);
211 waiter.task = task;
212 waiter.up = 0;
213
214 for (;;) {
215 if (signal_pending_state(state, task))
216 goto interrupted;
217 if (timeout <= 0)
218 goto timed_out;
219 __set_task_state(task, state);
220 spin_unlock_irq(&sem->lock);
221 timeout = schedule_timeout(timeout);
222 spin_lock_irq(&sem->lock);
223 if (waiter.up)
224 return 0;
225 }
226
227 timed_out:
228 list_del(&waiter.list);
229 return -ETIME;
230
231 interrupted:
232 list_del(&waiter.list);
233 return -EINTR;
234}
235
236static noinline void __sched __down(struct semaphore *sem)
237{
238 __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
239}
240
241static noinline int __sched __down_interruptible(struct semaphore *sem)
242{
243 return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
244}
245
246static noinline int __sched __down_killable(struct semaphore *sem)
247{
248 return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT);
249}
250
251static noinline int __sched __down_timeout(struct semaphore *sem, long jiffies)
252{
253 return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies);
254}
255
256static noinline void __sched __up(struct semaphore *sem)
257{
258 struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
259 struct semaphore_waiter, list);
260 list_del(&waiter->list);
261 waiter->up = 1;
262 wake_up_process(waiter->task);
263}
264