git: 6d720cdfe735 - main - linuxkpi: Add `woken_wake_function()` and `wait_woken()`
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 12 May 2025 17:46:47 UTC
The branch main has been updated by dumbbell: URL: https://cgit.FreeBSD.org/src/commit/?id=6d720cdfe7350d1eed620f1456bbe76ead708c30 commit 6d720cdfe7350d1eed620f1456bbe76ead708c30 Author: Jean-Sébastien Pédron <dumbbell@FreeBSD.org> AuthorDate: 2024-12-27 21:43:59 +0000 Commit: Jean-Sébastien Pédron <dumbbell@FreeBSD.org> CommitDate: 2025-05-12 17:08:02 +0000 linuxkpi: Add `woken_wake_function()` and `wait_woken()` They are used by the i915 DRM driver starting with Linux 6.7. `(struct wait_queue)->flags` is no longer always zero. I wonder if some code relied on this... Reviewed by: markj Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D48755 --- sys/compat/linuxkpi/common/include/linux/wait.h | 14 ++++-- sys/compat/linuxkpi/common/src/linux_schedule.c | 59 +++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h index bd496793e27e..03ddce2c06f5 100644 --- a/sys/compat/linuxkpi/common/include/linux/wait.h +++ b/sys/compat/linuxkpi/common/include/linux/wait.h @@ -61,12 +61,14 @@ typedef struct wait_queue_head wait_queue_head_t; typedef int wait_queue_func_t(wait_queue_t *, unsigned int, int, void *); +#define WQ_FLAG_WOKEN 0x02 + /* * Many API consumers directly reference these fields and those of * wait_queue_head. */ struct wait_queue { - unsigned int flags; /* always 0 */ + unsigned int flags; void *private; wait_queue_func_t *func; union { @@ -87,8 +89,14 @@ struct wait_queue_head { * This function is referenced by at least one DRM driver, so it may not be * renamed and furthermore must be the default wait queue callback. */ -extern wait_queue_func_t autoremove_wake_function; -extern wait_queue_func_t default_wake_function; +wait_queue_func_t autoremove_wake_function; +wait_queue_func_t default_wake_function; +wait_queue_func_t woken_wake_function; + +long linux_wait_woken(wait_queue_t *wq, unsigned state, long timeout); + +#define wait_woken(wq, state, timeout) \ + linux_wait_woken((wq), (state), (timeout)) #define DEFINE_WAIT_FUNC(name, function) \ wait_queue_t name = { \ diff --git a/sys/compat/linuxkpi/common/src/linux_schedule.c b/sys/compat/linuxkpi/common/src/linux_schedule.c index 3f3605096d62..c6b7a2ebbd66 100644 --- a/sys/compat/linuxkpi/common/src/linux_schedule.c +++ b/sys/compat/linuxkpi/common/src/linux_schedule.c @@ -200,6 +200,65 @@ default_wake_function(wait_queue_t *wq, unsigned int state, int flags, return (wake_up_task(wq->private, state)); } +long +linux_wait_woken(wait_queue_t *wq, unsigned state, long timeout) +{ + void *wchan; + struct task_struct *task; + int ret; + int remainder; + + task = current; + wchan = wq->private; + + remainder = jiffies + timeout; + + set_task_state(task, state); + + sleepq_lock(wchan); + if (!(wq->flags & WQ_FLAG_WOKEN)) { + ret = linux_add_to_sleepqueue(wchan, task, "woken", + timeout, state); + } else { + sleepq_release(wchan); + ret = 0; + } + + set_task_state(task, TASK_RUNNING); + wq->flags &= ~WQ_FLAG_WOKEN; + + if (timeout == MAX_SCHEDULE_TIMEOUT) + return (MAX_SCHEDULE_TIMEOUT); + + /* range check return value */ + remainder -= jiffies; + + /* range check return value */ + if (ret == -ERESTARTSYS && remainder < 1) + remainder = 1; + else if (remainder < 0) + remainder = 0; + else if (remainder > timeout) + remainder = timeout; + return (remainder); +} + +int +woken_wake_function(wait_queue_t *wq, unsigned int state, + int flags __unused, void *key __unused) +{ + void *wchan; + + wchan = wq->private; + + sleepq_lock(wchan); + wq->flags |= WQ_FLAG_WOKEN; + sleepq_signal(wchan, SLEEPQ_SLEEP, 0, 0); + sleepq_release(wchan); + + return (1); +} + void linux_init_wait_entry(wait_queue_t *wq, int flags) {