Commit 0db87bc9 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] SMP signal latency fix

The code that sends a signal needs to "kick" the target process if it
runs on another CPU and wasn't woken up by the signal to let it know
that it has a new event.

Otherwise it might take a long time until the target actually notices
and acts on the signal.
parent ae40e4b5
...@@ -574,7 +574,11 @@ extern void do_timer(struct pt_regs *); ...@@ -574,7 +574,11 @@ extern void do_timer(struct pt_regs *);
extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
extern int FASTCALL(wake_up_process(struct task_struct * tsk)); extern int FASTCALL(wake_up_process(struct task_struct * tsk));
extern int FASTCALL(wake_up_process_kick(struct task_struct * tsk)); #ifdef CONFIG_SMP
extern void FASTCALL(kick_process(struct task_struct * tsk));
#else
static inline void kick_process(struct task_struct *tsk) { }
#endif
extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk)); extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk));
extern void FASTCALL(sched_exit(task_t * p)); extern void FASTCALL(sched_exit(task_t * p));
......
...@@ -530,6 +530,15 @@ static inline void resched_task(task_t *p) ...@@ -530,6 +530,15 @@ static inline void resched_task(task_t *p)
#endif #endif
} }
/**
* task_curr - is this task currently executing on a CPU?
* @p: the task in question.
*/
inline int task_curr(task_t *p)
{
return cpu_curr(task_cpu(p)) == p;
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
...@@ -568,6 +577,27 @@ void wait_task_inactive(task_t * p) ...@@ -568,6 +577,27 @@ void wait_task_inactive(task_t * p)
task_rq_unlock(rq, &flags); task_rq_unlock(rq, &flags);
preempt_enable(); preempt_enable();
} }
/***
* kick_process - kick a running thread to enter/exit the kernel
* @p: the to-be-kicked thread
*
* Cause a process which is running on another CPU to enter
* kernel-mode, without any delay. (to get signals handled.)
*/
void kick_process(task_t *p)
{
int cpu;
preempt_disable();
cpu = task_cpu(p);
if ((cpu != smp_processor_id()) && task_curr(p))
smp_send_reschedule(cpu);
preempt_enable();
}
EXPORT_SYMBOL_GPL(kick_process);
#endif #endif
/*** /***
...@@ -575,7 +605,6 @@ void wait_task_inactive(task_t * p) ...@@ -575,7 +605,6 @@ void wait_task_inactive(task_t * p)
* @p: the to-be-woken-up thread * @p: the to-be-woken-up thread
* @state: the mask of task states that can be woken * @state: the mask of task states that can be woken
* @sync: do a synchronous wakeup? * @sync: do a synchronous wakeup?
* @kick: kick the CPU if the task is already running?
* *
* Put it on the run-queue if it's not already there. The "current" * Put it on the run-queue if it's not already there. The "current"
* thread is always on the run-queue (except when the actual * thread is always on the run-queue (except when the actual
...@@ -585,7 +614,7 @@ void wait_task_inactive(task_t * p) ...@@ -585,7 +614,7 @@ void wait_task_inactive(task_t * p)
* *
* returns failure only if the task is already active. * returns failure only if the task is already active.
*/ */
static int try_to_wake_up(task_t * p, unsigned int state, int sync, int kick) static int try_to_wake_up(task_t * p, unsigned int state, int sync)
{ {
unsigned long flags; unsigned long flags;
int success = 0; int success = 0;
...@@ -626,33 +655,22 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync, int kick) ...@@ -626,33 +655,22 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync, int kick)
} }
success = 1; success = 1;
} }
#ifdef CONFIG_SMP
else
if (unlikely(kick) && task_running(rq, p) && (task_cpu(p) != smp_processor_id()))
smp_send_reschedule(task_cpu(p));
#endif
p->state = TASK_RUNNING; p->state = TASK_RUNNING;
} }
task_rq_unlock(rq, &flags); task_rq_unlock(rq, &flags);
return success; return success;
} }
int wake_up_process(task_t * p) int wake_up_process(task_t * p)
{ {
return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 0); return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0);
} }
EXPORT_SYMBOL(wake_up_process); EXPORT_SYMBOL(wake_up_process);
int wake_up_process_kick(task_t * p)
{
return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 1);
}
int wake_up_state(task_t *p, unsigned int state) int wake_up_state(task_t *p, unsigned int state)
{ {
return try_to_wake_up(p, state, 0, 0); return try_to_wake_up(p, state, 0);
} }
/* /*
...@@ -1621,7 +1639,7 @@ EXPORT_SYMBOL(preempt_schedule); ...@@ -1621,7 +1639,7 @@ EXPORT_SYMBOL(preempt_schedule);
int default_wake_function(wait_queue_t *curr, unsigned mode, int sync) int default_wake_function(wait_queue_t *curr, unsigned mode, int sync)
{ {
task_t *p = curr->task; task_t *p = curr->task;
return try_to_wake_up(p, mode, sync, 0); return try_to_wake_up(p, mode, sync);
} }
EXPORT_SYMBOL(default_wake_function); EXPORT_SYMBOL(default_wake_function);
...@@ -1941,15 +1959,6 @@ int task_nice(task_t *p) ...@@ -1941,15 +1959,6 @@ int task_nice(task_t *p)
EXPORT_SYMBOL(task_nice); EXPORT_SYMBOL(task_nice);
/**
* task_curr - is this task currently executing on a CPU?
* @p: the task in question.
*/
int task_curr(task_t *p)
{
return cpu_curr(task_cpu(p)) == p;
}
/** /**
* idle_cpu - is a given cpu idle currently? * idle_cpu - is a given cpu idle currently?
* @cpu: the processor in question. * @cpu: the processor in question.
......
...@@ -538,8 +538,9 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) ...@@ -538,8 +538,9 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
inline void signal_wake_up(struct task_struct *t, int resume) inline void signal_wake_up(struct task_struct *t, int resume)
{ {
unsigned int mask; unsigned int mask;
int woken;
set_tsk_thread_flag(t,TIF_SIGPENDING); set_tsk_thread_flag(t, TIF_SIGPENDING);
/* /*
* If resume is set, we want to wake it up in the TASK_STOPPED case. * If resume is set, we want to wake it up in the TASK_STOPPED case.
...@@ -551,10 +552,11 @@ inline void signal_wake_up(struct task_struct *t, int resume) ...@@ -551,10 +552,11 @@ inline void signal_wake_up(struct task_struct *t, int resume)
mask = TASK_INTERRUPTIBLE; mask = TASK_INTERRUPTIBLE;
if (resume) if (resume)
mask |= TASK_STOPPED; mask |= TASK_STOPPED;
if (t->state & mask) { woken = 0;
wake_up_process_kick(t); if (t->state & mask)
return; woken = wake_up_state(t, mask);
} if (!woken)
kick_process(t);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment