Skip to content

Commit 0d09582

Browse files
committed
sched/wait: Add a waitqueue helper for fully exclusive priority waiters
Add a waitqueue helper to add a priority waiter that requires exclusive wakeups, i.e. that requires that it be the _only_ priority waiter. The API will be used by KVM to ensure that at most one of KVM's irqfds is bound to a single eventfd (across the entire kernel). Open code the helper instead of using __add_wait_queue() so that the common path doesn't need to "handle" impossible failures. Cc: K Prateek Nayak <kprateek.nayak@amd.com> Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com> Tested-by: K Prateek Nayak <kprateek.nayak@amd.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20250522235223.3178519-9-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent a526641 commit 0d09582

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

include/linux/wait.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ static inline bool wq_has_sleeper(struct wait_queue_head *wq_head)
164164
extern void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
165165
extern void add_wait_queue_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
166166
extern void add_wait_queue_priority(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
167+
extern int add_wait_queue_priority_exclusive(struct wait_queue_head *wq_head,
168+
struct wait_queue_entry *wq_entry);
167169
extern void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
168170

169171
static inline void __add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)

kernel/sched/wait.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,24 @@ void add_wait_queue_priority(struct wait_queue_head *wq_head, struct wait_queue_
4747
}
4848
EXPORT_SYMBOL_GPL(add_wait_queue_priority);
4949

50+
int add_wait_queue_priority_exclusive(struct wait_queue_head *wq_head,
51+
struct wait_queue_entry *wq_entry)
52+
{
53+
struct list_head *head = &wq_head->head;
54+
55+
wq_entry->flags |= WQ_FLAG_EXCLUSIVE | WQ_FLAG_PRIORITY;
56+
57+
guard(spinlock_irqsave)(&wq_head->lock);
58+
59+
if (!list_empty(head) &&
60+
(list_first_entry(head, typeof(*wq_entry), entry)->flags & WQ_FLAG_PRIORITY))
61+
return -EBUSY;
62+
63+
list_add(&wq_entry->entry, head);
64+
return 0;
65+
}
66+
EXPORT_SYMBOL_GPL(add_wait_queue_priority_exclusive);
67+
5068
void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
5169
{
5270
unsigned long flags;

0 commit comments

Comments
 (0)