diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 5812e01..db0e6c3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -222,7 +222,7 @@ static int ec_poll(struct acpi_ec *ec) if (ec_transaction_done(ec)) return 0; } else { - if (wait_event_timeout(ec->wait, + if (swait_event_timeout(ec->wait, ec_transaction_done(ec), msecs_to_jiffies(1))) return 0; @@ -272,7 +272,7 @@ static int ec_wait_ibf0(struct acpi_ec *ec) unsigned long delay = jiffies + msecs_to_jiffies(ec_delay); /* interrupt wait manually if GPE mode is not active */ while (time_before(jiffies, delay)) - if (wait_event_timeout(ec->wait, ec_check_ibf0(ec), + if (swait_event_timeout(ec->wait, ec_check_ibf0(ec), msecs_to_jiffies(1))) return 0; return -ETIME; @@ -612,7 +612,7 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, advance_transaction(ec, acpi_ec_read_status(ec)); if (ec_transaction_done(ec) && (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { - wake_up(&ec->wait); + swait_wake(&ec->wait); ec_check_sci(ec, acpi_ec_read_status(ec)); } return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; @@ -676,7 +676,7 @@ static struct acpi_ec *make_acpi_ec(void) return NULL; ec->flags = 1 << EC_FLAGS_QUERY_PENDING; mutex_init(&ec->lock); - init_waitqueue_head(&ec->wait); + init_swait_head(&ec->wait); INIT_LIST_HEAD(&ec->list); raw_spin_lock_init(&ec->curr_lock); return ec; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 68ed95f..2519b6e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -23,6 +23,8 @@ #define PREFIX "ACPI: " +#include + int init_acpi_device_notify(void); int acpi_scan_init(void); int acpi_sysfs_init(void); @@ -59,7 +61,7 @@ struct acpi_ec { unsigned long global_lock; unsigned long flags; struct mutex lock; - wait_queue_head_t wait; + struct swait_head wait; struct list_head list; struct transaction *curr; raw_spinlock_t curr_lock; diff --git a/include/linux/wait-simple.h b/include/linux/wait-simple.h new file mode 100644 index 0000000..de69d8a --- /dev/null +++ b/include/linux/wait-simple.h @@ -0,0 +1,152 @@ +#ifndef _LINUX_WAIT_SIMPLE_H +#define _LINUX_WAIT_SIMPLE_H + +#include +#include + +#include + +struct swaiter { + struct task_struct *task; + struct list_head node; +}; + +#define DEFINE_SWAITER(name) \ + struct swaiter name = { \ + .task = current, \ + .node = LIST_HEAD_INIT((name).node), \ + } + +struct swait_head { + raw_spinlock_t lock; + struct list_head list; +}; + +#define DEFINE_SWAIT_HEAD(name) \ + struct swait_head name = { \ + .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ + .list = LIST_HEAD_INIT((name).list), \ + } + +extern void __init_swait_head(struct swait_head *h, struct lock_class_key *key); + +#define init_swait_head(swh) \ + do { \ + static struct lock_class_key __key; \ + \ + __init_swait_head((swh), &__key); \ + } while (0) + +/* + * Waiter functions + */ +static inline bool swaiter_enqueued(struct swaiter *w) +{ + return w->task != NULL; +} + +extern void swait_prepare(struct swait_head *head, struct swaiter *w, int state); +extern void swait_finish(struct swait_head *head, struct swaiter *w); + +/* + * Adds w to head->list. Must be called with head->lock locked. + */ +static inline void __swait_enqueue(struct swait_head *head, struct swaiter *w) +{ + list_add(&w->node, &head->list); +} + +/* + * Removes w from head->list. Must be called with head->lock locked. + */ +static inline void __swait_dequeue(struct swaiter *w) +{ + list_del_init(&w->node); +} + +/* + * Wakeup functions + */ +extern void __swait_wake(struct swait_head *head, unsigned int state); + +static inline void swait_wake(struct swait_head *head) +{ + __swait_wake(head, TASK_NORMAL); +} + +/* + * Event API + */ + +#define __swait_event(wq, condition) \ +do { \ + DEFINE_SWAITER(__wait); \ + \ + for (;;) { \ + swait_prepare(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + schedule(); \ + } \ + swait_finish(&wq, &__wait); \ +} while (0) + +/** + * swait_event - sleep until a condition gets true + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * + * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + */ +#define swait_event(wq, condition) \ +do { \ + if (condition) \ + break; \ + __swait_event(wq, condition); \ +} while (0) + +#define __swait_event_timeout(wq, condition, ret) \ +do { \ + DEFINE_SWAITER(__wait); \ + \ + for (;;) { \ + swait_prepare(&wq, &__wait, TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + } \ + swait_finish(&wq, &__wait); \ +} while (0) + +/** + * swait_event_timeout - sleep until a condition gets true or a timeout elapses + * @wq: the waitqueue to wait on + * @condition: a C expression for the event to wait for + * @timeout: timeout, in jiffies + * + * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the + * @condition evaluates to true. The @condition is checked each time + * the waitqueue @wq is woken up. + * + * wake_up() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function returns 0 if the @timeout elapsed, and the remaining + * jiffies if the condition evaluated to true before the timeout elapsed. + */ +#define swait_event_timeout(wq, condition, timeout) \ +({ \ + long __ret = timeout; \ + if (!(condition)) \ + __swait_event_timeout(wq, condition, __ret); \ + __ret; \ +}) + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index 11949f1..6a9558b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,7 +10,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o \ hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \ notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \ - async.o range.o jump_label.o + async.o range.o wait-simple.o jump_label.o obj-y += groups.o ifdef CONFIG_FUNCTION_TRACER diff --git a/kernel/sched.c b/kernel/sched.c index 63aeba0..e5ef7a8 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2693,8 +2693,10 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) * if the wakeup condition is true. */ if (!(wake_flags & WF_LOCK_SLEEPER)) { - if (p->saved_state & state) + if (p->saved_state & state) { p->saved_state = TASK_RUNNING; + success = 1; + } } goto out; } diff --git a/kernel/wait-simple.c b/kernel/wait-simple.c new file mode 100644 index 0000000..35cc000 --- /dev/null +++ b/kernel/wait-simple.c @@ -0,0 +1,63 @@ +/* + * Simple waitqueues without fancy flags and callbacks + * + * (C) 2011 Thomas Gleixner + * + * Based on kernel/wait.c + * + * For licencing details see kernel-base/COPYING + */ +#include +#include +#include +#include + +void __init_swait_head(struct swait_head *head, struct lock_class_key *key) +{ + raw_spin_lock_init(&head->lock); + lockdep_set_class(&head->lock, key); + INIT_LIST_HEAD(&head->list); +} +EXPORT_SYMBOL_GPL(__init_swait_head); + +void swait_prepare(struct swait_head *head, struct swaiter *w, int state) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&head->lock, flags); + w->task = current; + __swait_enqueue(head, w); + set_current_state(state); + raw_spin_unlock_irqrestore(&head->lock, flags); +} +EXPORT_SYMBOL_GPL(swait_prepare); + +void swait_finish(struct swait_head *head, struct swaiter *w) +{ + unsigned long flags; + + __set_current_state(TASK_RUNNING); + if (w->task) { + raw_spin_lock_irqsave(&head->lock, flags); + __swait_dequeue(w); + raw_spin_unlock_irqrestore(&head->lock, flags); + } +} +EXPORT_SYMBOL_GPL(swait_finish); + +void __swait_wake(struct swait_head *head, unsigned int state) +{ + struct swaiter *curr, *next; + unsigned long flags; + + raw_spin_lock_irqsave(&head->lock, flags); + + list_for_each_entry_safe(curr, next, &head->list, node) { + if (wake_up_state(curr->task, state)) { + __swait_dequeue(curr); + curr->task = NULL; + } + } + + raw_spin_unlock_irqrestore(&head->lock, flags); +} diff --git a/localversion-rt b/localversion-rt index a68b433..ce6a482 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt31 +-rt32