aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/semaphore.c64
1 files changed, 34 insertions, 30 deletions
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
index 5e41217239e8..5c2942e768cd 100644
--- a/kernel/semaphore.c
+++ b/kernel/semaphore.c
@@ -54,9 +54,10 @@ void down(struct semaphore *sem)
54 unsigned long flags; 54 unsigned long flags;
55 55
56 spin_lock_irqsave(&sem->lock, flags); 56 spin_lock_irqsave(&sem->lock, flags);
57 if (unlikely(!sem->count)) 57 if (likely(sem->count > 0))
58 sem->count--;
59 else
58 __down(sem); 60 __down(sem);
59 sem->count--;
60 spin_unlock_irqrestore(&sem->lock, flags); 61 spin_unlock_irqrestore(&sem->lock, flags);
61} 62}
62EXPORT_SYMBOL(down); 63EXPORT_SYMBOL(down);
@@ -76,10 +77,10 @@ int down_interruptible(struct semaphore *sem)
76 int result = 0; 77 int result = 0;
77 78
78 spin_lock_irqsave(&sem->lock, flags); 79 spin_lock_irqsave(&sem->lock, flags);
79 if (unlikely(!sem->count)) 80 if (likely(sem->count > 0))
80 result = __down_interruptible(sem);
81 if (!result)
82 sem->count--; 81 sem->count--;
82 else
83 result = __down_interruptible(sem);
83 spin_unlock_irqrestore(&sem->lock, flags); 84 spin_unlock_irqrestore(&sem->lock, flags);
84 85
85 return result; 86 return result;
@@ -102,10 +103,10 @@ int down_killable(struct semaphore *sem)
102 int result = 0; 103 int result = 0;
103 104
104 spin_lock_irqsave(&sem->lock, flags); 105 spin_lock_irqsave(&sem->lock, flags);
105 if (unlikely(!sem->count)) 106 if (likely(sem->count > 0))
106 result = __down_killable(sem);
107 if (!result)
108 sem->count--; 107 sem->count--;
108 else
109 result = __down_killable(sem);
109 spin_unlock_irqrestore(&sem->lock, flags); 110 spin_unlock_irqrestore(&sem->lock, flags);
110 111
111 return result; 112 return result;
@@ -156,10 +157,10 @@ int down_timeout(struct semaphore *sem, long jiffies)
156 int result = 0; 157 int result = 0;
157 158
158 spin_lock_irqsave(&sem->lock, flags); 159 spin_lock_irqsave(&sem->lock, flags);
159 if (unlikely(!sem->count)) 160 if (likely(sem->count > 0))
160 result = __down_timeout(sem, jiffies);
161 if (!result)
162 sem->count--; 161 sem->count--;
162 else
163 result = __down_timeout(sem, jiffies);
163 spin_unlock_irqrestore(&sem->lock, flags); 164 spin_unlock_irqrestore(&sem->lock, flags);
164 165
165 return result; 166 return result;
@@ -178,8 +179,9 @@ void up(struct semaphore *sem)
178 unsigned long flags; 179 unsigned long flags;
179 180
180 spin_lock_irqsave(&sem->lock, flags); 181 spin_lock_irqsave(&sem->lock, flags);
181 sem->count++; 182 if (likely(list_empty(&sem->wait_list)))
182 if (unlikely(!list_empty(&sem->wait_list))) 183 sem->count++;
184 else
183 __up(sem); 185 __up(sem);
184 spin_unlock_irqrestore(&sem->lock, flags); 186 spin_unlock_irqrestore(&sem->lock, flags);
185} 187}
@@ -190,6 +192,7 @@ EXPORT_SYMBOL(up);
190struct semaphore_waiter { 192struct semaphore_waiter {
191 struct list_head list; 193 struct list_head list;
192 struct task_struct *task; 194 struct task_struct *task;
195 int up;
193}; 196};
194 197
195/* 198/*
@@ -202,34 +205,33 @@ static inline int __sched __down_common(struct semaphore *sem, long state,
202{ 205{
203 struct task_struct *task = current; 206 struct task_struct *task = current;
204 struct semaphore_waiter waiter; 207 struct semaphore_waiter waiter;
205 int ret = 0;
206 208
207 waiter.task = task;
208 list_add_tail(&waiter.list, &sem->wait_list); 209 list_add_tail(&waiter.list, &sem->wait_list);
210 waiter.task = task;
211 waiter.up = 0;
209 212
210 for (;;) { 213 for (;;) {
211 if (state == TASK_INTERRUPTIBLE && signal_pending(task)) { 214 if (state == TASK_INTERRUPTIBLE && signal_pending(task))
212 ret = -EINTR; 215 goto interrupted;
213 break; 216 if (state == TASK_KILLABLE && fatal_signal_pending(task))
214 } 217 goto interrupted;
215 if (state == TASK_KILLABLE && fatal_signal_pending(task)) { 218 if (timeout <= 0)
216 ret = -EINTR; 219 goto timed_out;
217 break;
218 }
219 if (timeout <= 0) {
220 ret = -ETIME;
221 break;
222 }
223 __set_task_state(task, state); 220 __set_task_state(task, state);
224 spin_unlock_irq(&sem->lock); 221 spin_unlock_irq(&sem->lock);
225 timeout = schedule_timeout(timeout); 222 timeout = schedule_timeout(timeout);
226 spin_lock_irq(&sem->lock); 223 spin_lock_irq(&sem->lock);
227 if (sem->count > 0) 224 if (waiter.up)
228 break; 225 return 0;
229 } 226 }
230 227
228 timed_out:
229 list_del(&waiter.list);
230 return -ETIME;
231
232 interrupted:
231 list_del(&waiter.list); 233 list_del(&waiter.list);
232 return ret; 234 return -EINTR;
233} 235}
234 236
235static noinline void __sched __down(struct semaphore *sem) 237static noinline void __sched __down(struct semaphore *sem)
@@ -256,5 +258,7 @@ static noinline void __sched __up(struct semaphore *sem)
256{ 258{
257 struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, 259 struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
258 struct semaphore_waiter, list); 260 struct semaphore_waiter, list);
261 list_del(&waiter->list);
262 waiter->up = 1;
259 wake_up_process(waiter->task); 263 wake_up_process(waiter->task);
260} 264}