162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2008 Intel Corporation 462306a36Sopenharmony_ci * Author: Matthew Wilcox <willy@linux.intel.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file implements counting semaphores. 762306a36Sopenharmony_ci * A counting semaphore may be acquired 'n' times before sleeping. 862306a36Sopenharmony_ci * See mutex.c for single-acquisition sleeping locks which enforce 962306a36Sopenharmony_ci * rules which allow code to be debugged more easily. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * Some notes on the implementation: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * The spinlock controls access to the other members of the semaphore. 1662306a36Sopenharmony_ci * down_trylock() and up() can be called from interrupt context, so we 1762306a36Sopenharmony_ci * have to disable interrupts when taking the lock. It turns out various 1862306a36Sopenharmony_ci * parts of the kernel expect to be able to use down() on a semaphore in 1962306a36Sopenharmony_ci * interrupt context when they know it will succeed, so we have to use 2062306a36Sopenharmony_ci * irqsave variants for down(), down_interruptible() and down_killable() 2162306a36Sopenharmony_ci * too. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * The ->count variable represents how many more tasks can acquire this 2462306a36Sopenharmony_ci * semaphore. If it's zero, there may be tasks waiting on the wait_list. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/compiler.h> 2862306a36Sopenharmony_ci#include <linux/kernel.h> 2962306a36Sopenharmony_ci#include <linux/export.h> 3062306a36Sopenharmony_ci#include <linux/sched.h> 3162306a36Sopenharmony_ci#include <linux/sched/debug.h> 3262306a36Sopenharmony_ci#include <linux/semaphore.h> 3362306a36Sopenharmony_ci#include <linux/spinlock.h> 3462306a36Sopenharmony_ci#include <linux/ftrace.h> 3562306a36Sopenharmony_ci#include <trace/events/lock.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic noinline void __down(struct semaphore *sem); 3862306a36Sopenharmony_cistatic noinline int __down_interruptible(struct semaphore *sem); 3962306a36Sopenharmony_cistatic noinline int __down_killable(struct semaphore *sem); 4062306a36Sopenharmony_cistatic noinline int __down_timeout(struct semaphore *sem, long timeout); 4162306a36Sopenharmony_cistatic noinline void __up(struct semaphore *sem); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * down - acquire the semaphore 4562306a36Sopenharmony_ci * @sem: the semaphore to be acquired 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Acquires the semaphore. If no more tasks are allowed to acquire the 4862306a36Sopenharmony_ci * semaphore, calling this function will put the task to sleep until the 4962306a36Sopenharmony_ci * semaphore is released. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Use of this function is deprecated, please use down_interruptible() or 5262306a36Sopenharmony_ci * down_killable() instead. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_civoid __sched down(struct semaphore *sem) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci unsigned long flags; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci might_sleep(); 5962306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 6062306a36Sopenharmony_ci if (likely(sem->count > 0)) 6162306a36Sopenharmony_ci sem->count--; 6262306a36Sopenharmony_ci else 6362306a36Sopenharmony_ci __down(sem); 6462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ciEXPORT_SYMBOL(down); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/** 6962306a36Sopenharmony_ci * down_interruptible - acquire the semaphore unless interrupted 7062306a36Sopenharmony_ci * @sem: the semaphore to be acquired 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * Attempts to acquire the semaphore. If no more tasks are allowed to 7362306a36Sopenharmony_ci * acquire the semaphore, calling this function will put the task to sleep. 7462306a36Sopenharmony_ci * If the sleep is interrupted by a signal, this function will return -EINTR. 7562306a36Sopenharmony_ci * If the semaphore is successfully acquired, this function returns 0. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ciint __sched down_interruptible(struct semaphore *sem) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned long flags; 8062306a36Sopenharmony_ci int result = 0; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci might_sleep(); 8362306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 8462306a36Sopenharmony_ci if (likely(sem->count > 0)) 8562306a36Sopenharmony_ci sem->count--; 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci result = __down_interruptible(sem); 8862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return result; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ciEXPORT_SYMBOL(down_interruptible); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * down_killable - acquire the semaphore unless killed 9662306a36Sopenharmony_ci * @sem: the semaphore to be acquired 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * Attempts to acquire the semaphore. If no more tasks are allowed to 9962306a36Sopenharmony_ci * acquire the semaphore, calling this function will put the task to sleep. 10062306a36Sopenharmony_ci * If the sleep is interrupted by a fatal signal, this function will return 10162306a36Sopenharmony_ci * -EINTR. If the semaphore is successfully acquired, this function returns 10262306a36Sopenharmony_ci * 0. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ciint __sched down_killable(struct semaphore *sem) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci unsigned long flags; 10762306a36Sopenharmony_ci int result = 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci might_sleep(); 11062306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 11162306a36Sopenharmony_ci if (likely(sem->count > 0)) 11262306a36Sopenharmony_ci sem->count--; 11362306a36Sopenharmony_ci else 11462306a36Sopenharmony_ci result = __down_killable(sem); 11562306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return result; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ciEXPORT_SYMBOL(down_killable); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/** 12262306a36Sopenharmony_ci * down_trylock - try to acquire the semaphore, without waiting 12362306a36Sopenharmony_ci * @sem: the semaphore to be acquired 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * Try to acquire the semaphore atomically. Returns 0 if the semaphore has 12662306a36Sopenharmony_ci * been acquired successfully or 1 if it cannot be acquired. 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * NOTE: This return value is inverted from both spin_trylock and 12962306a36Sopenharmony_ci * mutex_trylock! Be careful about this when converting code. 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Unlike mutex_trylock, this function can be used from interrupt context, 13262306a36Sopenharmony_ci * and the semaphore can be released by any task or interrupt. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ciint __sched down_trylock(struct semaphore *sem) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci unsigned long flags; 13762306a36Sopenharmony_ci int count; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 14062306a36Sopenharmony_ci count = sem->count - 1; 14162306a36Sopenharmony_ci if (likely(count >= 0)) 14262306a36Sopenharmony_ci sem->count = count; 14362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return (count < 0); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ciEXPORT_SYMBOL(down_trylock); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/** 15062306a36Sopenharmony_ci * down_timeout - acquire the semaphore within a specified time 15162306a36Sopenharmony_ci * @sem: the semaphore to be acquired 15262306a36Sopenharmony_ci * @timeout: how long to wait before failing 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Attempts to acquire the semaphore. If no more tasks are allowed to 15562306a36Sopenharmony_ci * acquire the semaphore, calling this function will put the task to sleep. 15662306a36Sopenharmony_ci * If the semaphore is not released within the specified number of jiffies, 15762306a36Sopenharmony_ci * this function returns -ETIME. It returns 0 if the semaphore was acquired. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ciint __sched down_timeout(struct semaphore *sem, long timeout) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned long flags; 16262306a36Sopenharmony_ci int result = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci might_sleep(); 16562306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 16662306a36Sopenharmony_ci if (likely(sem->count > 0)) 16762306a36Sopenharmony_ci sem->count--; 16862306a36Sopenharmony_ci else 16962306a36Sopenharmony_ci result = __down_timeout(sem, timeout); 17062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return result; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ciEXPORT_SYMBOL(down_timeout); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/** 17762306a36Sopenharmony_ci * up - release the semaphore 17862306a36Sopenharmony_ci * @sem: the semaphore to release 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Release the semaphore. Unlike mutexes, up() may be called from any 18162306a36Sopenharmony_ci * context and even by tasks which have never called down(). 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_civoid __sched up(struct semaphore *sem) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci unsigned long flags; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci raw_spin_lock_irqsave(&sem->lock, flags); 18862306a36Sopenharmony_ci if (likely(list_empty(&sem->wait_list))) 18962306a36Sopenharmony_ci sem->count++; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci __up(sem); 19262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&sem->lock, flags); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ciEXPORT_SYMBOL(up); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* Functions for the contended case */ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistruct semaphore_waiter { 19962306a36Sopenharmony_ci struct list_head list; 20062306a36Sopenharmony_ci struct task_struct *task; 20162306a36Sopenharmony_ci bool up; 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/* 20562306a36Sopenharmony_ci * Because this function is inlined, the 'state' parameter will be 20662306a36Sopenharmony_ci * constant, and thus optimised away by the compiler. Likewise the 20762306a36Sopenharmony_ci * 'timeout' parameter for the cases without timeouts. 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic inline int __sched ___down_common(struct semaphore *sem, long state, 21062306a36Sopenharmony_ci long timeout) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct semaphore_waiter waiter; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci list_add_tail(&waiter.list, &sem->wait_list); 21562306a36Sopenharmony_ci waiter.task = current; 21662306a36Sopenharmony_ci waiter.up = false; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci for (;;) { 21962306a36Sopenharmony_ci if (signal_pending_state(state, current)) 22062306a36Sopenharmony_ci goto interrupted; 22162306a36Sopenharmony_ci if (unlikely(timeout <= 0)) 22262306a36Sopenharmony_ci goto timed_out; 22362306a36Sopenharmony_ci __set_current_state(state); 22462306a36Sopenharmony_ci raw_spin_unlock_irq(&sem->lock); 22562306a36Sopenharmony_ci timeout = schedule_timeout(timeout); 22662306a36Sopenharmony_ci raw_spin_lock_irq(&sem->lock); 22762306a36Sopenharmony_ci if (waiter.up) 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci timed_out: 23262306a36Sopenharmony_ci list_del(&waiter.list); 23362306a36Sopenharmony_ci return -ETIME; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci interrupted: 23662306a36Sopenharmony_ci list_del(&waiter.list); 23762306a36Sopenharmony_ci return -EINTR; 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic inline int __sched __down_common(struct semaphore *sem, long state, 24162306a36Sopenharmony_ci long timeout) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci int ret; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci trace_contention_begin(sem, 0); 24662306a36Sopenharmony_ci ret = ___down_common(sem, state, timeout); 24762306a36Sopenharmony_ci trace_contention_end(sem, ret); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic noinline void __sched __down(struct semaphore *sem) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic noinline int __sched __down_interruptible(struct semaphore *sem) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic noinline int __sched __down_killable(struct semaphore *sem) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic noinline int __sched __down_timeout(struct semaphore *sem, long timeout) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic noinline void __sched __up(struct semaphore *sem) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, 27562306a36Sopenharmony_ci struct semaphore_waiter, list); 27662306a36Sopenharmony_ci list_del(&waiter->list); 27762306a36Sopenharmony_ci waiter->up = true; 27862306a36Sopenharmony_ci wake_up_process(waiter->task); 27962306a36Sopenharmony_ci} 280