diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h --- a/sys/compat/linuxkpi/common/include/linux/wait.h +++ b/sys/compat/linuxkpi/common/include/linux/wait.h @@ -61,12 +61,14 @@ 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 { @@ -89,6 +91,9 @@ */ extern wait_queue_func_t autoremove_wake_function; extern wait_queue_func_t default_wake_function; +extern wait_queue_func_t woken_wake_function; + +long wait_woken(wait_queue_t *wq, unsigned state, long 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 --- a/sys/compat/linuxkpi/common/src/linux_schedule.c +++ b/sys/compat/linuxkpi/common/src/linux_schedule.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -182,6 +183,30 @@ return (wake_up_task(wq->private, state)); } +int +woken_wake_function(wait_queue_t *wq, unsigned int state, int flags, + void *key) +{ + smp_mb(); + wq->flags |= WQ_FLAG_WOKEN; + + return (default_wake_function(wq, state, flags, key)); +} + +long +wait_woken(wait_queue_t *wq, unsigned state, long timeout) +{ + set_task_state(current, state); + if (!(wq->flags & WQ_FLAG_WOKEN)) { + timeout = linux_schedule_timeout(timeout); + } + set_task_state(current, TASK_RUNNING); + + smp_store_mb(wq->flags, wq->flags & ~WQ_FLAG_WOKEN); + + return (timeout); +} + void linux_init_wait_entry(wait_queue_t *wq, int flags) {