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