Messages in this thread Patch in this message | | | Subject | [PATCH] [2.4] Waitable counter structure | From | Luca Barbieri <> | Date | 30 May 2002 20:11:53 +0200 |
| |
"Waitable counter": object that keeps a count and allows to wait until it reaches zero or is no longer zero.
Sample usage: keep track of requests and, on driver shutdown, wait for completion of all the requests (counter goes to 0) before completing the shutdown (an alternative design is to have the last request completed perform the shutdown, but this isn't always possible).
Actually having to do something like the sample seems so common that it seems strange that there isn't already something to handle this. Am I an obvious simpler way of doing this? (other than scheduling in a loop, which is unelegant and inappropriate if the task might wait for a long time)
diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/include/linux/waitcount.h linux/include/linux/waitcount.h --- linux-base/include/linux/waitcount.h Thu Jan 1 01:00:00 1970 +++ linux/include/linux/waitcount.h Thu May 30 16:28:45 2002 @@ -0,0 +1,67 @@ +#ifndef __LINUX_WAITCOUNT_H +#define __LINUX_WAITCOUNT_H + +#include <linux/config.h> +#include <linux/wait.h> +#include <asm/atomic.h> + +/* "Waitable counter": object that keeps a count and allows to wait + until it reaches zero or is no longer zero. + */ + +struct waitable_count { + atomic_t count; + wait_queue_head_t waitq; +}; + + +#define __WAITABLE_COUNT_INITIALIZER(name) (struct waitable_count) {ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).waitq)} +#define INITIALIZE_WAITABLE_COUNT(name) (name) = __WAITABLE_COUNT_INITIALIZER(name) +#define DECLARE_WAITABLE_COUNT(name) struct waitable_count name = __WAITABLE_COUNT_INITIALIZER(name) + +static inline void +inc_count(struct waitable_count *wcount) +{ + atomic_inc(&wcount->count); +} + +static inline void +dec_count_wake_up(struct waitable_count *wcount) +{ + if (atomic_dec_and_test(&wcount->count) && waitqueue_active(&wcount->waitq)) { + wake_up_all(&wcount->waitq); + } +} + +static inline void +inc_count_wake_up(struct waitable_count *wcount) +{ + if (!atomic_inc_and_test(&wcount->count) && waitqueue_active(&wcount->waitq)) { + wake_up_all(&wcount->waitq); + } +} + +static inline void +dec_count(struct waitable_count *wcount) +{ + atomic_dec(&wcount->count); +} + +#define inc_nonzero inc_count_wake_up +#define dec_nonzero dec_count +#define inc_zero inc_count +#define dec_zero dec_count_wake_up + +void +__wait_count(struct waitable_count *wcount, int nonzero, int state); + +static inline void +wait_count(struct waitable_count *wcount, int nonzero, int state) +{ + if (!atomic_read(&wcount->count) == nonzero) + { + __wait_count (wcount, nonzero, state); + } +} + +#endif diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/kernel/ksyms.c linux/kernel/ksyms.c --- linux-base/kernel/ksyms.c Wed Apr 10 14:37:33 2002 +++ linux/kernel/ksyms.c Thu May 30 16:29:13 2002 @@ -47,6 +47,7 @@ #include <linux/in6.h> #include <linux/completion.h> #include <linux/seq_file.h> +#include <linux/waitcount.h> #include <asm/checksum.h> #if defined(CONFIG_PROC_FS) @@ -472,6 +473,7 @@ EXPORT_SYMBOL(sleep_on_timeout); EXPORT_SYMBOL(interruptible_sleep_on); EXPORT_SYMBOL(interruptible_sleep_on_timeout); +EXPORT_SYMBOL(__wait_count); EXPORT_SYMBOL(schedule); EXPORT_SYMBOL(schedule_timeout); EXPORT_SYMBOL(jiffies); diff --exclude-from=/home/ldb/src/linux-exclude -u -r -N linux-base/kernel/sched.c linux/kernel/sched.c --- linux-base/kernel/sched.c Wed Apr 10 14:37:29 2002 +++ linux/kernel/sched.c Thu May 30 16:29:28 2002 @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <linux/completion.h> +#include <linux/waitcount.h> #include <linux/prefetch.h> #include <linux/compiler.h> @@ -851,6 +852,22 @@ SLEEP_ON_TAIL return timeout; +} + +void +__wait_count(struct waitable_count *wcount, int nonzero, int state) +{ +#define q (&wcount->waitq) + SLEEP_ON_VAR + + current->state = state; + + SLEEP_ON_HEAD + if (!atomic_read(&wcount->count) == nonzero) + schedule(); + current->state = TASK_RUNNING; + SLEEP_ON_TAIL +#undef q } void scheduling_functions_end_here(void) { }[unhandled content-type:application/pgp-signature] | |