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#include <linux/sched.h>
27
28#include <asm/semaphore.h>
29
30
31
32
33
34
35
36
37
38
39
40void
41__up (struct semaphore *sem)
42{
43 wake_up(&sem->wait);
44}
45
46static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
47
48void
49__down (struct semaphore *sem)
50{
51 struct task_struct *tsk = current;
52 DECLARE_WAITQUEUE(wait, tsk);
53 tsk->state = TASK_UNINTERRUPTIBLE;
54 add_wait_queue_exclusive(&sem->wait, &wait);
55
56 spin_lock_irq(&semaphore_lock);
57 sem->sleepers++;
58 for (;;) {
59 int sleepers = sem->sleepers;
60
61
62
63
64
65 if (!atomic_add_negative(sleepers - 1, &sem->count)) {
66 sem->sleepers = 0;
67 break;
68 }
69 sem->sleepers = 1;
70 spin_unlock_irq(&semaphore_lock);
71
72 schedule();
73 tsk->state = TASK_UNINTERRUPTIBLE;
74 spin_lock_irq(&semaphore_lock);
75 }
76 spin_unlock_irq(&semaphore_lock);
77 remove_wait_queue(&sem->wait, &wait);
78 tsk->state = TASK_RUNNING;
79 wake_up(&sem->wait);
80}
81
82int
83__down_interruptible (struct semaphore * sem)
84{
85 int retval = 0;
86 struct task_struct *tsk = current;
87 DECLARE_WAITQUEUE(wait, tsk);
88 tsk->state = TASK_INTERRUPTIBLE;
89 add_wait_queue_exclusive(&sem->wait, &wait);
90
91 spin_lock_irq(&semaphore_lock);
92 sem->sleepers ++;
93 for (;;) {
94 int sleepers = sem->sleepers;
95
96
97
98
99
100
101
102
103 if (signal_pending(current)) {
104 retval = -EINTR;
105 sem->sleepers = 0;
106 atomic_add(sleepers, &sem->count);
107 break;
108 }
109
110
111
112
113
114
115
116 if (!atomic_add_negative(sleepers - 1, &sem->count)) {
117 sem->sleepers = 0;
118 break;
119 }
120 sem->sleepers = 1;
121 spin_unlock_irq(&semaphore_lock);
122
123 schedule();
124 tsk->state = TASK_INTERRUPTIBLE;
125 spin_lock_irq(&semaphore_lock);
126 }
127 spin_unlock_irq(&semaphore_lock);
128 tsk->state = TASK_RUNNING;
129 remove_wait_queue(&sem->wait, &wait);
130 wake_up(&sem->wait);
131 return retval;
132}
133
134
135
136
137
138int
139__down_trylock (struct semaphore *sem)
140{
141 unsigned long flags;
142 int sleepers;
143
144 spin_lock_irqsave(&semaphore_lock, flags);
145 sleepers = sem->sleepers + 1;
146 sem->sleepers = 0;
147
148
149
150
151
152 if (!atomic_add_negative(sleepers, &sem->count))
153 wake_up(&sem->wait);
154
155 spin_unlock_irqrestore(&semaphore_lock, flags);
156 return 1;
157}
158