]> git.sesse.net Git - bcachefs-tools-debian/blob - linux/semaphore.c
Disable pristine-tar option in gbp.conf, since there is no pristine-tar branch.
[bcachefs-tools-debian] / linux / semaphore.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2008 Intel Corporation
4  * Author: Matthew Wilcox <willy@linux.intel.com>
5  *
6  * This file implements counting semaphores.
7  * A counting semaphore may be acquired 'n' times before sleeping.
8  * See mutex.c for single-acquisition sleeping locks which enforce
9  * rules which allow code to be debugged more easily.
10  */
11
12 /*
13  * Some notes on the implementation:
14  *
15  * The spinlock controls access to the other members of the semaphore.
16  * down_trylock() and up() can be called from interrupt context, so we
17  * have to disable interrupts when taking the lock.  It turns out various
18  * parts of the kernel expect to be able to use down() on a semaphore in
19  * interrupt context when they know it will succeed, so we have to use
20  * irqsave variants for down(), down_interruptible() and down_killable()
21  * too.
22  *
23  * The ->count variable represents how many more tasks can acquire this
24  * semaphore.  If it's zero, there may be tasks waiting on the wait_list.
25  */
26
27 #include <linux/compiler.h>
28 #include <linux/kernel.h>
29 #include <linux/export.h>
30 #include <linux/sched.h>
31 #include <linux/semaphore.h>
32 #include <linux/spinlock.h>
33
34 static noinline void __down(struct semaphore *sem);
35 static noinline int __down_timeout(struct semaphore *sem, long timeout);
36 static noinline void __up(struct semaphore *sem);
37
38 /**
39  * down - acquire the semaphore
40  * @sem: the semaphore to be acquired
41  *
42  * Acquires the semaphore.  If no more tasks are allowed to acquire the
43  * semaphore, calling this function will put the task to sleep until the
44  * semaphore is released.
45  *
46  * Use of this function is deprecated, please use down_interruptible() or
47  * down_killable() instead.
48  */
49 void down(struct semaphore *sem)
50 {
51         unsigned long flags;
52
53         raw_spin_lock_irqsave(&sem->lock, flags);
54         if (likely(sem->count > 0))
55                 sem->count--;
56         else
57                 __down(sem);
58         raw_spin_unlock_irqrestore(&sem->lock, flags);
59 }
60 EXPORT_SYMBOL(down);
61
62 /**
63  * down_trylock - try to acquire the semaphore, without waiting
64  * @sem: the semaphore to be acquired
65  *
66  * Try to acquire the semaphore atomically.  Returns 0 if the semaphore has
67  * been acquired successfully or 1 if it it cannot be acquired.
68  *
69  * NOTE: This return value is inverted from both spin_trylock and
70  * mutex_trylock!  Be careful about this when converting code.
71  *
72  * Unlike mutex_trylock, this function can be used from interrupt context,
73  * and the semaphore can be released by any task or interrupt.
74  */
75 int down_trylock(struct semaphore *sem)
76 {
77         unsigned long flags;
78         int count;
79
80         raw_spin_lock_irqsave(&sem->lock, flags);
81         count = sem->count - 1;
82         if (likely(count >= 0))
83                 sem->count = count;
84         raw_spin_unlock_irqrestore(&sem->lock, flags);
85
86         return (count < 0);
87 }
88 EXPORT_SYMBOL(down_trylock);
89
90 /**
91  * down_timeout - acquire the semaphore within a specified time
92  * @sem: the semaphore to be acquired
93  * @timeout: how long to wait before failing
94  *
95  * Attempts to acquire the semaphore.  If no more tasks are allowed to
96  * acquire the semaphore, calling this function will put the task to sleep.
97  * If the semaphore is not released within the specified number of jiffies,
98  * this function returns -ETIME.  It returns 0 if the semaphore was acquired.
99  */
100 int down_timeout(struct semaphore *sem, long timeout)
101 {
102         unsigned long flags;
103         int result = 0;
104
105         raw_spin_lock_irqsave(&sem->lock, flags);
106         if (likely(sem->count > 0))
107                 sem->count--;
108         else
109                 result = __down_timeout(sem, timeout);
110         raw_spin_unlock_irqrestore(&sem->lock, flags);
111
112         return result;
113 }
114 EXPORT_SYMBOL(down_timeout);
115
116 /**
117  * up - release the semaphore
118  * @sem: the semaphore to release
119  *
120  * Release the semaphore.  Unlike mutexes, up() may be called from any
121  * context and even by tasks which have never called down().
122  */
123 void up(struct semaphore *sem)
124 {
125         unsigned long flags;
126
127         raw_spin_lock_irqsave(&sem->lock, flags);
128         if (likely(list_empty(&sem->wait_list)))
129                 sem->count++;
130         else
131                 __up(sem);
132         raw_spin_unlock_irqrestore(&sem->lock, flags);
133 }
134 EXPORT_SYMBOL(up);
135
136 /* Functions for the contended case */
137
138 struct semaphore_waiter {
139         struct list_head list;
140         struct task_struct *task;
141         bool up;
142 };
143
144 /*
145  * Because this function is inlined, the 'state' parameter will be
146  * constant, and thus optimised away by the compiler.  Likewise the
147  * 'timeout' parameter for the cases without timeouts.
148  */
149 static inline int __sched __down_common(struct semaphore *sem, long state,
150                                                                 long timeout)
151 {
152         struct semaphore_waiter waiter;
153
154         list_add_tail(&waiter.list, &sem->wait_list);
155         waiter.task = current;
156         waiter.up = false;
157
158         for (;;) {
159                 if (unlikely(timeout <= 0))
160                         goto timed_out;
161                 __set_current_state(state);
162                 raw_spin_unlock_irq(&sem->lock);
163                 timeout = schedule_timeout(timeout);
164                 raw_spin_lock_irq(&sem->lock);
165                 if (waiter.up)
166                         return 0;
167         }
168
169  timed_out:
170         list_del(&waiter.list);
171         return -ETIME;
172 }
173
174 static noinline void __sched __down(struct semaphore *sem)
175 {
176         __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
177 }
178
179 static noinline int __sched __down_timeout(struct semaphore *sem, long timeout)
180 {
181         return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout);
182 }
183
184 static noinline void __sched __up(struct semaphore *sem)
185 {
186         struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
187                                                 struct semaphore_waiter, list);
188         list_del(&waiter->list);
189         waiter->up = true;
190         wake_up_process(waiter->task);
191 }