mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-05-14 21:38:46 +02:00
b9bdd4b684
Instead of embedding a list_head in struct semaphore, store a pointer to the first waiter. The list of waiters remains a doubly linked list so we can efficiently add to the tail of the list and remove from the front (or middle) of the list. Some of the list manipulation becomes more complicated, but it's a reasonable tradeoff on the slow paths to shrink data structures which embed a semaphore. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260305195545.3707590-3-willy@infradead.org
65 lines
1.9 KiB
C
65 lines
1.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2008 Intel Corporation
|
|
* Author: Matthew Wilcox <willy@linux.intel.com>
|
|
*
|
|
* Please see kernel/locking/semaphore.c for documentation of these functions
|
|
*/
|
|
#ifndef __LINUX_SEMAPHORE_H
|
|
#define __LINUX_SEMAPHORE_H
|
|
|
|
#include <linux/list.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
/* Please don't access any members of this structure directly */
|
|
struct semaphore {
|
|
raw_spinlock_t lock;
|
|
unsigned int count;
|
|
struct semaphore_waiter *first_waiter;
|
|
|
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
|
unsigned long last_holder;
|
|
#endif
|
|
};
|
|
|
|
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
|
|
#define __LAST_HOLDER_SEMAPHORE_INITIALIZER \
|
|
, .last_holder = 0UL
|
|
#else
|
|
#define __LAST_HOLDER_SEMAPHORE_INITIALIZER
|
|
#endif
|
|
|
|
#define __SEMAPHORE_INITIALIZER(name, n) \
|
|
{ \
|
|
.lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock), \
|
|
.count = n, \
|
|
.first_waiter = NULL \
|
|
__LAST_HOLDER_SEMAPHORE_INITIALIZER \
|
|
}
|
|
|
|
/*
|
|
* Unlike mutexes, binary semaphores do not have an owner, so up() can
|
|
* be called in a different thread from the one which called down().
|
|
* It is also safe to call down_trylock() and up() from interrupt
|
|
* context.
|
|
*/
|
|
#define DEFINE_SEMAPHORE(_name, _n) \
|
|
struct semaphore _name = __SEMAPHORE_INITIALIZER(_name, _n)
|
|
|
|
static inline void sema_init(struct semaphore *sem, int val)
|
|
{
|
|
static struct lock_class_key __key;
|
|
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
|
|
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
|
|
}
|
|
|
|
extern void down(struct semaphore *sem);
|
|
extern int __must_check down_interruptible(struct semaphore *sem);
|
|
extern int __must_check down_killable(struct semaphore *sem);
|
|
extern int __must_check down_trylock(struct semaphore *sem);
|
|
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
|
|
extern void up(struct semaphore *sem);
|
|
extern unsigned long sem_last_holder(struct semaphore *sem);
|
|
|
|
#endif /* __LINUX_SEMAPHORE_H */
|