89 lines
2.9 KiB
Diff
89 lines
2.9 KiB
Diff
Subject: sched-rt-mutex-wakeup.patch
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Sat, 25 Jun 2011 09:21:04 +0200
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
---
|
|
include/linux/sched.h | 3 +++
|
|
kernel/sched.c | 31 ++++++++++++++++++++++++++++++-
|
|
2 files changed, 33 insertions(+), 1 deletion(-)
|
|
|
|
Index: linux-3.2/include/linux/sched.h
|
|
===================================================================
|
|
--- linux-3.2.orig/include/linux/sched.h
|
|
+++ linux-3.2/include/linux/sched.h
|
|
@@ -1072,6 +1072,7 @@ struct sched_domain;
|
|
#define WF_SYNC 0x01 /* waker goes to sleep after wakup */
|
|
#define WF_FORK 0x02 /* child wakeup after fork */
|
|
#define WF_MIGRATED 0x04 /* internal use, task got migrated */
|
|
+#define WF_LOCK_SLEEPER 0x08 /* wakeup spinlock "sleeper" */
|
|
|
|
#define ENQUEUE_WAKEUP 1
|
|
#define ENQUEUE_HEAD 2
|
|
@@ -1221,6 +1222,7 @@ enum perf_event_task_context {
|
|
|
|
struct task_struct {
|
|
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
|
|
+ volatile long saved_state; /* saved state for "spinlock sleepers" */
|
|
void *stack;
|
|
atomic_t usage;
|
|
unsigned int flags; /* per process flags, defined below */
|
|
@@ -2178,6 +2180,7 @@ extern void xtime_update(unsigned long t
|
|
|
|
extern int wake_up_state(struct task_struct *tsk, unsigned int state);
|
|
extern int wake_up_process(struct task_struct *tsk);
|
|
+extern int wake_up_lock_sleeper(struct task_struct * tsk);
|
|
extern void wake_up_new_task(struct task_struct *tsk);
|
|
#ifdef CONFIG_SMP
|
|
extern void kick_process(struct task_struct *tsk);
|
|
Index: linux-3.2/kernel/sched.c
|
|
===================================================================
|
|
--- linux-3.2.orig/kernel/sched.c
|
|
+++ linux-3.2/kernel/sched.c
|
|
@@ -2827,8 +2827,25 @@ try_to_wake_up(struct task_struct *p, un
|
|
|
|
smp_wmb();
|
|
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
|
- if (!(p->state & state))
|
|
+ if (!(p->state & state)) {
|
|
+ /*
|
|
+ * The task might be running due to a spinlock sleeper
|
|
+ * wakeup. Check the saved state and set it to running
|
|
+ * if the wakeup condition is true.
|
|
+ */
|
|
+ if (!(wake_flags & WF_LOCK_SLEEPER)) {
|
|
+ if (p->saved_state & state)
|
|
+ p->saved_state = TASK_RUNNING;
|
|
+ }
|
|
goto out;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * If this is a regular wakeup, then we can unconditionally
|
|
+ * clear the saved state of a "lock sleeper".
|
|
+ */
|
|
+ if (!(wake_flags & WF_LOCK_SLEEPER))
|
|
+ p->saved_state = TASK_RUNNING;
|
|
|
|
success = 1; /* we're going to change ->state */
|
|
cpu = task_cpu(p);
|
|
@@ -2900,6 +2917,18 @@ int wake_up_process(struct task_struct *
|
|
}
|
|
EXPORT_SYMBOL(wake_up_process);
|
|
|
|
+/**
|
|
+ * wake_up_lock_sleeper - Wake up a specific process blocked on a "sleeping lock"
|
|
+ * @p: The process to be woken up.
|
|
+ *
|
|
+ * Same as wake_up_process() above, but wake_flags=WF_LOCK_SLEEPER to indicate
|
|
+ * the nature of the wakeup.
|
|
+ */
|
|
+int wake_up_lock_sleeper(struct task_struct *p)
|
|
+{
|
|
+ return try_to_wake_up(p, TASK_ALL, WF_LOCK_SLEEPER);
|
|
+}
|
|
+
|
|
int wake_up_state(struct task_struct *p, unsigned int state)
|
|
{
|
|
return try_to_wake_up(p, state, 0);
|