aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/semaphore.h39
-rw-r--r--kernel/semaphore.c79
2 files changed, 70 insertions, 48 deletions
diff --git a/include/linux/semaphore.h b/include/linux/semaphore.h
index a7125daaff90..9cae64b00d6b 100644
--- a/include/linux/semaphore.h
+++ b/include/linux/semaphore.h
@@ -4,8 +4,7 @@
4 * 4 *
5 * Distributed under the terms of the GNU GPL, version 2 5 * Distributed under the terms of the GNU GPL, version 2
6 * 6 *
7 * Counting semaphores allow up to <n> tasks to acquire the semaphore 7 * Please see kernel/semaphore.c for documentation of these functions
8 * simultaneously.
9 */ 8 */
10#ifndef __LINUX_SEMAPHORE_H 9#ifndef __LINUX_SEMAPHORE_H
11#define __LINUX_SEMAPHORE_H 10#define __LINUX_SEMAPHORE_H
@@ -13,11 +12,7 @@
13#include <linux/list.h> 12#include <linux/list.h>
14#include <linux/spinlock.h> 13#include <linux/spinlock.h>
15 14
16/* 15/* Please don't access any members of this structure directly */
17 * The spinlock controls access to the other members of the semaphore.
18 * 'count' represents how many more tasks can acquire this semaphore.
19 * Tasks waiting for the lock are kept on the wait_list.
20 */
21struct semaphore { 16struct semaphore {
22 spinlock_t lock; 17 spinlock_t lock;
23 unsigned int count; 18 unsigned int count;
@@ -46,41 +41,11 @@ static inline void sema_init(struct semaphore *sem, int val)
46#define init_MUTEX(sem) sema_init(sem, 1) 41#define init_MUTEX(sem) sema_init(sem, 1)
47#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) 42#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
48 43
49/*
50 * Attempt to acquire the semaphore. If another task is already holding the
51 * semaphore, sleep until the semaphore is released.
52 */
53extern void down(struct semaphore *sem); 44extern void down(struct semaphore *sem);
54
55/*
56 * As down(), except the sleep may be interrupted by a signal. If it is,
57 * this function will return -EINTR.
58 */
59extern int __must_check down_interruptible(struct semaphore *sem); 45extern int __must_check down_interruptible(struct semaphore *sem);
60
61/*
62 * As down_interruptible(), except the sleep may only be interrupted by
63 * signals which are fatal to this process.
64 */
65extern int __must_check down_killable(struct semaphore *sem); 46extern int __must_check down_killable(struct semaphore *sem);
66
67/*
68 * As down(), except this function will not sleep. It will return 0 if it
69 * acquired the semaphore and 1 if the semaphore was contended. This
70 * function may be called from any context, including interrupt and softirq.
71 */
72extern int __must_check down_trylock(struct semaphore *sem); 47extern int __must_check down_trylock(struct semaphore *sem);
73
74/*
75 * As down(), except this function will return -ETIME if it fails to
76 * acquire the semaphore within the specified number of jiffies.
77 */
78extern int __must_check down_timeout(struct semaphore *sem, long jiffies); 48extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
79
80/*
81 * Release the semaphore. Unlike mutexes, up() may be called from any
82 * context and even by tasks which have never called down().
83 */
84extern void up(struct semaphore *sem); 49extern void up(struct semaphore *sem);
85 50
86#endif /* __LINUX_SEMAPHORE_H */ 51#endif /* __LINUX_SEMAPHORE_H */
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
index bef977b16966..5c2942e768cd 100644
--- a/kernel/semaphore.c
+++ b/kernel/semaphore.c
@@ -3,6 +3,26 @@
3 * Author: Matthew Wilcox <willy@linux.intel.com> 3 * Author: Matthew Wilcox <willy@linux.intel.com>
4 * 4 *
5 * Distributed under the terms of the GNU GPL, version 2 5 * Distributed under the terms of the GNU GPL, version 2
6 *
7 * This file implements counting semaphores.
8 * A counting semaphore may be acquired 'n' times before sleeping.
9 * See mutex.c for single-acquisition sleeping locks which enforce
10 * rules which allow code to be debugged more easily.
11 */
12
13/*
14 * Some notes on the implementation:
15 *
16 * The spinlock controls access to the other members of the semaphore.
17 * down_trylock() and up() can be called from interrupt context, so we
18 * have to disable interrupts when taking the lock. It turns out various
19 * parts of the kernel expect to be able to use down() on a semaphore in
20 * interrupt context when they know it will succeed, so we have to use
21 * irqsave variants for down(), down_interruptible() and down_killable()
22 * too.
23 *
24 * The ->count variable represents how many more tasks can acquire this
25 * semaphore. If it's zero, there may be tasks waiting on the wait_list.
6 */ 26 */
7 27
8#include <linux/compiler.h> 28#include <linux/compiler.h>
@@ -12,22 +32,23 @@
12#include <linux/semaphore.h> 32#include <linux/semaphore.h>
13#include <linux/spinlock.h> 33#include <linux/spinlock.h>
14 34
15/*
16 * Some notes on the implementation:
17 *
18 * down_trylock() and up() can be called from interrupt context.
19 * So we have to disable interrupts when taking the lock.
20 *
21 * The ->count variable defines how many more tasks can acquire the
22 * semaphore. If it's zero, there may be tasks waiting on the list.
23 */
24
25static noinline void __down(struct semaphore *sem); 35static noinline void __down(struct semaphore *sem);
26static noinline int __down_interruptible(struct semaphore *sem); 36static noinline int __down_interruptible(struct semaphore *sem);
27static noinline int __down_killable(struct semaphore *sem); 37static noinline int __down_killable(struct semaphore *sem);
28static noinline int __down_timeout(struct semaphore *sem, long jiffies); 38static noinline int __down_timeout(struct semaphore *sem, long jiffies);
29static noinline void __up(struct semaphore *sem); 39static noinline void __up(struct semaphore *sem);
30 40
41/**
42 * down - acquire the semaphore
43 * @sem: the semaphore to be acquired
44 *
45 * Acquires the semaphore. If no more tasks are allowed to acquire the
46 * semaphore, calling this function will put the task to sleep until the
47 * semaphore is released.
48 *
49 * Use of this function is deprecated, please use down_interruptible() or
50 * down_killable() instead.
51 */
31void down(struct semaphore *sem) 52void down(struct semaphore *sem)
32{ 53{
33 unsigned long flags; 54 unsigned long flags;
@@ -41,6 +62,15 @@ void down(struct semaphore *sem)
41} 62}
42EXPORT_SYMBOL(down); 63EXPORT_SYMBOL(down);
43 64
65/**
66 * down_interruptible - acquire the semaphore unless interrupted
67 * @sem: the semaphore to be acquired
68 *
69 * Attempts to acquire the semaphore. If no more tasks are allowed to
70 * acquire the semaphore, calling this function will put the task to sleep.
71 * If the sleep is interrupted by a signal, this function will return -EINTR.
72 * If the semaphore is successfully acquired, this function returns 0.
73 */
44int down_interruptible(struct semaphore *sem) 74int down_interruptible(struct semaphore *sem)
45{ 75{
46 unsigned long flags; 76 unsigned long flags;
@@ -57,6 +87,16 @@ int down_interruptible(struct semaphore *sem)
57} 87}
58EXPORT_SYMBOL(down_interruptible); 88EXPORT_SYMBOL(down_interruptible);
59 89
90/**
91 * down_killable - acquire the semaphore unless killed
92 * @sem: the semaphore to be acquired
93 *
94 * Attempts to acquire the semaphore. If no more tasks are allowed to
95 * acquire the semaphore, calling this function will put the task to sleep.
96 * If the sleep is interrupted by a fatal signal, this function will return
97 * -EINTR. If the semaphore is successfully acquired, this function returns
98 * 0.
99 */
60int down_killable(struct semaphore *sem) 100int down_killable(struct semaphore *sem)
61{ 101{
62 unsigned long flags; 102 unsigned long flags;
@@ -78,7 +118,7 @@ EXPORT_SYMBOL(down_killable);
78 * @sem: the semaphore to be acquired 118 * @sem: the semaphore to be acquired
79 * 119 *
80 * Try to acquire the semaphore atomically. Returns 0 if the mutex has 120 * Try to acquire the semaphore atomically. Returns 0 if the mutex has
81 * been acquired successfully and 1 if it is contended. 121 * been acquired successfully or 1 if it it cannot be acquired.
82 * 122 *
83 * NOTE: This return value is inverted from both spin_trylock and 123 * NOTE: This return value is inverted from both spin_trylock and
84 * mutex_trylock! Be careful about this when converting code. 124 * mutex_trylock! Be careful about this when converting code.
@@ -101,6 +141,16 @@ int down_trylock(struct semaphore *sem)
101} 141}
102EXPORT_SYMBOL(down_trylock); 142EXPORT_SYMBOL(down_trylock);
103 143
144/**
145 * down_timeout - acquire the semaphore within a specified time
146 * @sem: the semaphore to be acquired
147 * @jiffies: how long to wait before failing
148 *
149 * Attempts to acquire the semaphore. If no more tasks are allowed to
150 * acquire the semaphore, calling this function will put the task to sleep.
151 * If the semaphore is not released within the specified number of jiffies,
152 * this function returns -ETIME. It returns 0 if the semaphore was acquired.
153 */
104int down_timeout(struct semaphore *sem, long jiffies) 154int down_timeout(struct semaphore *sem, long jiffies)
105{ 155{
106 unsigned long flags; 156 unsigned long flags;
@@ -117,6 +167,13 @@ int down_timeout(struct semaphore *sem, long jiffies)
117} 167}
118EXPORT_SYMBOL(down_timeout); 168EXPORT_SYMBOL(down_timeout);
119 169
170/**
171 * up - release the semaphore
172 * @sem: the semaphore to release
173 *
174 * Release the semaphore. Unlike mutexes, up() may be called from any
175 * context and even by tasks which have never called down().
176 */
120void up(struct semaphore *sem) 177void up(struct semaphore *sem)
121{ 178{
122 unsigned long flags; 179 unsigned long flags;