diff options
-rw-r--r-- | include/linux/semaphore.h | 6 | ||||
-rw-r--r-- | kernel/semaphore.c | 22 |
2 files changed, 28 insertions, 0 deletions
diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h index b3c691b089b2..88f2a28cc0f1 100644 --- a/include/linux/semaphore.h +++ b/include/linux/semaphore.h | |||
@@ -62,6 +62,12 @@ extern void down(struct semaphore *sem); | |||
62 | extern int __must_check down_interruptible(struct semaphore *sem); | 62 | extern int __must_check down_interruptible(struct semaphore *sem); |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * As down_interruptible(), except the sleep may only be interrupted by | ||
66 | * signals which are fatal to this process. | ||
67 | */ | ||
68 | extern int __must_check down_killable(struct semaphore *sem); | ||
69 | |||
70 | /* | ||
65 | * As down(), except this function will not sleep. It will return 0 if it | 71 | * As down(), except this function will not sleep. It will return 0 if it |
66 | * acquired the semaphore and 1 if the semaphore was contended. This | 72 | * acquired the semaphore and 1 if the semaphore was contended. This |
67 | * function may be called from any context, including interrupt and softirq. | 73 | * function may be called from any context, including interrupt and softirq. |
diff --git a/kernel/semaphore.c b/kernel/semaphore.c index d5a72702f261..2da2aed950f3 100644 --- a/kernel/semaphore.c +++ b/kernel/semaphore.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | static noinline void __down(struct semaphore *sem); | 35 | static noinline void __down(struct semaphore *sem); |
36 | static noinline int __down_interruptible(struct semaphore *sem); | 36 | static noinline int __down_interruptible(struct semaphore *sem); |
37 | static noinline int __down_killable(struct semaphore *sem); | ||
37 | static noinline void __up(struct semaphore *sem); | 38 | static noinline void __up(struct semaphore *sem); |
38 | 39 | ||
39 | void down(struct semaphore *sem) | 40 | void down(struct semaphore *sem) |
@@ -61,6 +62,20 @@ int down_interruptible(struct semaphore *sem) | |||
61 | } | 62 | } |
62 | EXPORT_SYMBOL(down_interruptible); | 63 | EXPORT_SYMBOL(down_interruptible); |
63 | 64 | ||
65 | int down_killable(struct semaphore *sem) | ||
66 | { | ||
67 | unsigned long flags; | ||
68 | int result = 0; | ||
69 | |||
70 | spin_lock_irqsave(&sem->lock, flags); | ||
71 | if (unlikely(sem->count-- <= 0)) | ||
72 | result = __down_killable(sem); | ||
73 | spin_unlock_irqrestore(&sem->lock, flags); | ||
74 | |||
75 | return result; | ||
76 | } | ||
77 | EXPORT_SYMBOL(down_killable); | ||
78 | |||
64 | /** | 79 | /** |
65 | * down_trylock - try to acquire the semaphore, without waiting | 80 | * down_trylock - try to acquire the semaphore, without waiting |
66 | * @sem: the semaphore to be acquired | 81 | * @sem: the semaphore to be acquired |
@@ -143,6 +158,8 @@ static inline int __sched __down_common(struct semaphore *sem, long state) | |||
143 | for (;;) { | 158 | for (;;) { |
144 | if (state == TASK_INTERRUPTIBLE && signal_pending(task)) | 159 | if (state == TASK_INTERRUPTIBLE && signal_pending(task)) |
145 | goto interrupted; | 160 | goto interrupted; |
161 | if (state == TASK_KILLABLE && fatal_signal_pending(task)) | ||
162 | goto interrupted; | ||
146 | __set_task_state(task, state); | 163 | __set_task_state(task, state); |
147 | spin_unlock_irq(&sem->lock); | 164 | spin_unlock_irq(&sem->lock); |
148 | schedule(); | 165 | schedule(); |
@@ -178,6 +195,11 @@ static noinline int __sched __down_interruptible(struct semaphore *sem) | |||
178 | return __down_common(sem, TASK_INTERRUPTIBLE); | 195 | return __down_common(sem, TASK_INTERRUPTIBLE); |
179 | } | 196 | } |
180 | 197 | ||
198 | static noinline int __sched __down_killable(struct semaphore *sem) | ||
199 | { | ||
200 | return __down_common(sem, TASK_KILLABLE); | ||
201 | } | ||
202 | |||
181 | static noinline void __sched __up(struct semaphore *sem) | 203 | static noinline void __sched __up(struct semaphore *sem) |
182 | { | 204 | { |
183 | if (unlikely(list_empty(&sem->wait_list))) | 205 | if (unlikely(list_empty(&sem->wait_list))) |