Branch data Line data Source code
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/sched/debug.h> 32 : : #include <linux/semaphore.h> 33 : : #include <linux/spinlock.h> 34 : : #include <linux/ftrace.h> 35 : : 36 : : static noinline void __down(struct semaphore *sem); 37 : : static noinline int __down_interruptible(struct semaphore *sem); 38 : : static noinline int __down_killable(struct semaphore *sem); 39 : : static noinline int __down_timeout(struct semaphore *sem, long timeout); 40 : : static noinline void __up(struct semaphore *sem); 41 : : 42 : : /** 43 : : * down - acquire the semaphore 44 : : * @sem: the semaphore to be acquired 45 : : * 46 : : * Acquires the semaphore. If no more tasks are allowed to acquire the 47 : : * semaphore, calling this function will put the task to sleep until the 48 : : * semaphore is released. 49 : : * 50 : : * Use of this function is deprecated, please use down_interruptible() or 51 : : * down_killable() instead. 52 : : */ 53 : 3 : void down(struct semaphore *sem) 54 : : { 55 : : unsigned long flags; 56 : : 57 : 3 : raw_spin_lock_irqsave(&sem->lock, flags); 58 : 3 : if (likely(sem->count > 0)) 59 : 3 : sem->count--; 60 : : else 61 : 3 : __down(sem); 62 : 3 : raw_spin_unlock_irqrestore(&sem->lock, flags); 63 : 3 : } 64 : : EXPORT_SYMBOL(down); 65 : : 66 : : /** 67 : : * down_interruptible - acquire the semaphore unless interrupted 68 : : * @sem: the semaphore to be acquired 69 : : * 70 : : * Attempts to acquire the semaphore. If no more tasks are allowed to 71 : : * acquire the semaphore, calling this function will put the task to sleep. 72 : : * If the sleep is interrupted by a signal, this function will return -EINTR. 73 : : * If the semaphore is successfully acquired, this function returns 0. 74 : : */ 75 : 3 : int down_interruptible(struct semaphore *sem) 76 : : { 77 : : unsigned long flags; 78 : : int result = 0; 79 : : 80 : 3 : raw_spin_lock_irqsave(&sem->lock, flags); 81 : 3 : if (likely(sem->count > 0)) 82 : 3 : sem->count--; 83 : : else 84 : 2 : result = __down_interruptible(sem); 85 : 3 : raw_spin_unlock_irqrestore(&sem->lock, flags); 86 : : 87 : 3 : return result; 88 : : } 89 : : EXPORT_SYMBOL(down_interruptible); 90 : : 91 : : /** 92 : : * down_killable - acquire the semaphore unless killed 93 : : * @sem: the semaphore to be acquired 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 sleep is interrupted by a fatal signal, this function will return 98 : : * -EINTR. If the semaphore is successfully acquired, this function returns 99 : : * 0. 100 : : */ 101 : 0 : int down_killable(struct semaphore *sem) 102 : : { 103 : : unsigned long flags; 104 : : int result = 0; 105 : : 106 : 0 : raw_spin_lock_irqsave(&sem->lock, flags); 107 : 0 : if (likely(sem->count > 0)) 108 : 0 : sem->count--; 109 : : else 110 : 0 : result = __down_killable(sem); 111 : 0 : raw_spin_unlock_irqrestore(&sem->lock, flags); 112 : : 113 : 0 : return result; 114 : : } 115 : : EXPORT_SYMBOL(down_killable); 116 : : 117 : : /** 118 : : * down_trylock - try to acquire the semaphore, without waiting 119 : : * @sem: the semaphore to be acquired 120 : : * 121 : : * Try to acquire the semaphore atomically. Returns 0 if the semaphore has 122 : : * been acquired successfully or 1 if it it cannot be acquired. 123 : : * 124 : : * NOTE: This return value is inverted from both spin_trylock and 125 : : * mutex_trylock! Be careful about this when converting code. 126 : : * 127 : : * Unlike mutex_trylock, this function can be used from interrupt context, 128 : : * and the semaphore can be released by any task or interrupt. 129 : : */ 130 : 3 : int down_trylock(struct semaphore *sem) 131 : : { 132 : : unsigned long flags; 133 : : int count; 134 : : 135 : 3 : raw_spin_lock_irqsave(&sem->lock, flags); 136 : 3 : count = sem->count - 1; 137 : 3 : if (likely(count >= 0)) 138 : 3 : sem->count = count; 139 : 3 : raw_spin_unlock_irqrestore(&sem->lock, flags); 140 : : 141 : 3 : return (count < 0); 142 : : } 143 : : EXPORT_SYMBOL(down_trylock); 144 : : 145 : : /** 146 : : * down_timeout - acquire the semaphore within a specified time 147 : : * @sem: the semaphore to be acquired 148 : : * @timeout: how long to wait before failing 149 : : * 150 : : * Attempts to acquire the semaphore. If no more tasks are allowed to 151 : : * acquire the semaphore, calling this function will put the task to sleep. 152 : : * If the semaphore is not released within the specified number of jiffies, 153 : : * this function returns -ETIME. It returns 0 if the semaphore was acquired. 154 : : */ 155 : 0 : int down_timeout(struct semaphore *sem, long timeout) 156 : : { 157 : : unsigned long flags; 158 : : int result = 0; 159 : : 160 : 0 : raw_spin_lock_irqsave(&sem->lock, flags); 161 : 0 : if (likely(sem->count > 0)) 162 : 0 : sem->count--; 163 : : else 164 : 0 : result = __down_timeout(sem, timeout); 165 : 0 : raw_spin_unlock_irqrestore(&sem->lock, flags); 166 : : 167 : 0 : return result; 168 : : } 169 : : EXPORT_SYMBOL(down_timeout); 170 : : 171 : : /** 172 : : * up - release the semaphore 173 : : * @sem: the semaphore to release 174 : : * 175 : : * Release the semaphore. Unlike mutexes, up() may be called from any 176 : : * context and even by tasks which have never called down(). 177 : : */ 178 : 3 : void up(struct semaphore *sem) 179 : : { 180 : : unsigned long flags; 181 : : 182 : 3 : raw_spin_lock_irqsave(&sem->lock, flags); 183 : 3 : if (likely(list_empty(&sem->wait_list))) 184 : 3 : sem->count++; 185 : : else 186 : 3 : __up(sem); 187 : 3 : raw_spin_unlock_irqrestore(&sem->lock, flags); 188 : 3 : } 189 : : EXPORT_SYMBOL(up); 190 : : 191 : : /* Functions for the contended case */ 192 : : 193 : : struct semaphore_waiter { 194 : : struct list_head list; 195 : : struct task_struct *task; 196 : : bool up; 197 : : }; 198 : : 199 : : /* 200 : : * Because this function is inlined, the 'state' parameter will be 201 : : * constant, and thus optimised away by the compiler. Likewise the 202 : : * 'timeout' parameter for the cases without timeouts. 203 : : */ 204 : 3 : static inline int __sched __down_common(struct semaphore *sem, long state, 205 : : long timeout) 206 : : { 207 : : struct semaphore_waiter waiter; 208 : : 209 : 3 : list_add_tail(&waiter.list, &sem->wait_list); 210 : 3 : waiter.task = current; 211 : 3 : waiter.up = false; 212 : : 213 : : for (;;) { 214 : 3 : if (signal_pending_state(state, current)) 215 : : goto interrupted; 216 : 3 : if (unlikely(timeout <= 0)) 217 : : goto timed_out; 218 : 3 : __set_current_state(state); 219 : 3 : raw_spin_unlock_irq(&sem->lock); 220 : 3 : timeout = schedule_timeout(timeout); 221 : 3 : raw_spin_lock_irq(&sem->lock); 222 : 3 : if (waiter.up) 223 : : return 0; 224 : : } 225 : : 226 : : timed_out: 227 : : list_del(&waiter.list); 228 : 0 : return -ETIME; 229 : : 230 : : interrupted: 231 : : list_del(&waiter.list); 232 : 0 : return -EINTR; 233 : : } 234 : : 235 : 3 : static noinline void __sched __down(struct semaphore *sem) 236 : : { 237 : 3 : __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); 238 : 3 : } 239 : : 240 : 2 : static noinline int __sched __down_interruptible(struct semaphore *sem) 241 : : { 242 : 2 : return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); 243 : : } 244 : : 245 : 0 : static noinline int __sched __down_killable(struct semaphore *sem) 246 : : { 247 : 0 : return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT); 248 : : } 249 : : 250 : 0 : static noinline int __sched __down_timeout(struct semaphore *sem, long timeout) 251 : : { 252 : 0 : return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout); 253 : : } 254 : : 255 : 3 : static noinline void __sched __up(struct semaphore *sem) 256 : : { 257 : 3 : struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, 258 : : struct semaphore_waiter, list); 259 : : list_del(&waiter->list); 260 : 3 : waiter->up = true; 261 : 3 : wake_up_process(waiter->task); 262 : 3 : }