1
2
3
4
5
6
7
8
9
10
11
12
13
14#include <linux/config.h>
15#include <linux/sched.h>
16
17#include <asm/semaphore.h>
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
50void __up(struct semaphore *sem)
51{
52 wake_up(&sem->wait);
53}
54
55static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
56
57void __down(struct semaphore * sem)
58{
59 struct task_struct *tsk = current;
60 DECLARE_WAITQUEUE(wait, tsk);
61 tsk->state = TASK_UNINTERRUPTIBLE;
62 add_wait_queue_exclusive(&sem->wait, &wait);
63
64 spin_lock_irq(&semaphore_lock);
65 sem->sleepers++;
66 for (;;) {
67 int sleepers = sem->sleepers;
68
69
70
71
72
73 if (!atomic_add_negative(sleepers - 1, &sem->count)) {
74 sem->sleepers = 0;
75 break;
76 }
77 sem->sleepers = 1;
78 spin_unlock_irq(&semaphore_lock);
79
80 schedule();
81 tsk->state = TASK_UNINTERRUPTIBLE;
82 spin_lock_irq(&semaphore_lock);
83 }
84 spin_unlock_irq(&semaphore_lock);
85 remove_wait_queue(&sem->wait, &wait);
86 tsk->state = TASK_RUNNING;
87 wake_up(&sem->wait);
88}
89
90int __down_interruptible(struct semaphore * sem)
91{
92 int retval = 0;
93 struct task_struct *tsk = current;
94 DECLARE_WAITQUEUE(wait, tsk);
95 tsk->state = TASK_INTERRUPTIBLE;
96 add_wait_queue_exclusive(&sem->wait, &wait);
97
98 spin_lock_irq(&semaphore_lock);
99 sem->sleepers ++;
100 for (;;) {
101 int sleepers = sem->sleepers;
102
103
104
105
106
107
108
109
110 if (signal_pending(current)) {
111 retval = -EINTR;
112 sem->sleepers = 0;
113 atomic_add(sleepers, &sem->count);
114 break;
115 }
116
117
118
119
120
121
122
123 if (!atomic_add_negative(sleepers - 1, &sem->count)) {
124 sem->sleepers = 0;
125 break;
126 }
127 sem->sleepers = 1;
128 spin_unlock_irq(&semaphore_lock);
129
130 schedule();
131 tsk->state = TASK_INTERRUPTIBLE;
132 spin_lock_irq(&semaphore_lock);
133 }
134 spin_unlock_irq(&semaphore_lock);
135 tsk->state = TASK_RUNNING;
136 remove_wait_queue(&sem->wait, &wait);
137 wake_up(&sem->wait);
138 return retval;
139}
140
141
142
143
144
145
146
147
148
149int __down_trylock(struct semaphore * sem)
150{
151 int sleepers;
152 unsigned long flags;
153
154 spin_lock_irqsave(&semaphore_lock, flags);
155 sleepers = sem->sleepers + 1;
156 sem->sleepers = 0;
157
158
159
160
161
162 if (!atomic_add_negative(sleepers, &sem->count))
163 wake_up(&sem->wait);
164
165 spin_unlock_irqrestore(&semaphore_lock, flags);
166 return 1;
167}
168
169
170
171
172
173
174
175
176
177
178
179#ifdef CONFIG_CPU_26
180asm(" .align 5
181 .globl __down_failed
182__down_failed:
183 stmfd sp!, {r0 - r3, lr}
184 mov r0, ip
185 bl __down
186 ldmfd sp!, {r0 - r3, pc}^
187
188 .align 5
189 .globl __down_interruptible_failed
190__down_interruptible_failed:
191 stmfd sp!, {r0 - r3, lr}
192 mov r0, ip
193 bl __down_interruptible
194 mov ip, r0
195 ldmfd sp!, {r0 - r3, pc}^
196
197 .align 5
198 .globl __down_trylock_failed
199__down_trylock_failed:
200 stmfd sp!, {r0 - r3, lr}
201 mov r0, ip
202 bl __down_trylock
203 mov ip, r0
204 ldmfd sp!, {r0 - r3, pc}^
205
206 .align 5
207 .globl __up_wakeup
208__up_wakeup:
209 stmfd sp!, {r0 - r3, lr}
210 mov r0, ip
211 bl __up
212 ldmfd sp!, {r0 - r3, pc}^
213
214 ");
215
216#else
217
218asm(" .align 5
219 .globl __down_failed
220__down_failed:
221 stmfd sp!, {r0 - r3, lr}
222 mov r0, ip
223 bl __down
224 ldmfd sp!, {r0 - r3, pc}
225
226 .align 5
227 .globl __down_interruptible_failed
228__down_interruptible_failed:
229 stmfd sp!, {r0 - r3, lr}
230 mov r0, ip
231 bl __down_interruptible
232 mov ip, r0
233 ldmfd sp!, {r0 - r3, pc}
234
235 .align 5
236 .globl __down_trylock_failed
237__down_trylock_failed:
238 stmfd sp!, {r0 - r3, lr}
239 mov r0, ip
240 bl __down_trylock
241 mov ip, r0
242 ldmfd sp!, {r0 - r3, pc}
243
244 .align 5
245 .globl __up_wakeup
246__up_wakeup:
247 stmfd sp!, {r0 - r3, lr}
248 mov r0, ip
249 bl __up
250 ldmfd sp!, {r0 - r3, pc}
251
252 ");
253
254#endif
255