1
2
3
4
5
6
7
8
9#include <linux/sched.h>
10
11
12
13
14
15
16
17
18
19
20static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
21{
22 int old_count, tmp;
23
24 __asm__ __volatile__("\n"
25" ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
26"1: ldsw [%3], %0\n"
27" mov %0, %1\n"
28" cmp %0, 0\n"
29" movl %%icc, 0, %1\n"
30" add %1, %4, %1\n"
31" cas [%3], %0, %1\n"
32" cmp %0, %1\n"
33" bne,pn %%icc, 1b\n"
34" membar #StoreLoad | #StoreStore\n"
35 : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
36 : "r" (&sem->count), "r" (incr), "m" (sem->count)
37 : "cc");
38
39 return old_count;
40}
41
42void __up(struct semaphore *sem)
43{
44 __sem_update_count(sem, 1);
45 wake_up(&sem->wait);
46}
47
48void __down(struct semaphore * sem)
49{
50 struct task_struct *tsk = current;
51 DECLARE_WAITQUEUE(wait, tsk);
52
53 tsk->state = TASK_UNINTERRUPTIBLE;
54 add_wait_queue_exclusive(&sem->wait, &wait);
55
56 while (__sem_update_count(sem, -1) <= 0) {
57 schedule();
58 tsk->state = TASK_UNINTERRUPTIBLE;
59 }
60 remove_wait_queue(&sem->wait, &wait);
61 tsk->state = TASK_RUNNING;
62
63 wake_up(&sem->wait);
64}
65
66int __down_interruptible(struct semaphore * sem)
67{
68 int retval = 0;
69 struct task_struct *tsk = current;
70 DECLARE_WAITQUEUE(wait, tsk);
71
72 tsk->state = TASK_INTERRUPTIBLE;
73 add_wait_queue_exclusive(&sem->wait, &wait);
74
75 while (__sem_update_count(sem, -1) <= 0) {
76 if (signal_pending(current)) {
77 __sem_update_count(sem, 0);
78 retval = -EINTR;
79 break;
80 }
81 schedule();
82 tsk->state = TASK_INTERRUPTIBLE;
83 }
84 tsk->state = TASK_RUNNING;
85 remove_wait_queue(&sem->wait, &wait);
86 wake_up(&sem->wait);
87 return retval;
88}
89