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