Commit 655ed59f authored by Linus Torvalds's avatar Linus Torvalds

Create "wake_up_state()" macro that selectively wakes up processes only

from certain states.

This simplifies "default_wake_function()", and makes it possible for
signal handling to wake up only the processes it _should_ wake up
without races.
parent b7517d19
...@@ -516,6 +516,7 @@ extern unsigned long itimer_ticks; ...@@ -516,6 +516,7 @@ extern unsigned long itimer_ticks;
extern unsigned long itimer_next; extern unsigned long itimer_next;
extern void do_timer(struct pt_regs *); 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_process(struct task_struct * tsk)); extern int FASTCALL(wake_up_process(struct task_struct * tsk));
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));
......
...@@ -438,6 +438,7 @@ void kick_if_running(task_t * p) ...@@ -438,6 +438,7 @@ void kick_if_running(task_t * p)
/*** /***
* try_to_wake_up - wake up a thread * try_to_wake_up - wake up a thread
* @p: the to-be-woken-up thread * @p: the to-be-woken-up thread
* @state: the mask of task states that can be woken
* @sync: do a synchronous wakeup? * @sync: do a synchronous wakeup?
* *
* 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"
...@@ -448,7 +449,7 @@ void kick_if_running(task_t * p) ...@@ -448,7 +449,7 @@ void kick_if_running(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, int sync) 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;
...@@ -458,6 +459,7 @@ static int try_to_wake_up(task_t * p, int sync) ...@@ -458,6 +459,7 @@ static int try_to_wake_up(task_t * p, int sync)
repeat_lock_task: repeat_lock_task:
rq = task_rq_lock(p, &flags); rq = task_rq_lock(p, &flags);
old_state = p->state; old_state = p->state;
if (old_state & state) {
if (!p->array) { if (!p->array) {
/* /*
* Fast-migrate the task if it's not running or runnable * Fast-migrate the task if it's not running or runnable
...@@ -480,6 +482,7 @@ static int try_to_wake_up(task_t * p, int sync) ...@@ -480,6 +482,7 @@ static int try_to_wake_up(task_t * p, int sync)
success = 1; success = 1;
} }
p->state = TASK_RUNNING; p->state = TASK_RUNNING;
}
task_rq_unlock(rq, &flags); task_rq_unlock(rq, &flags);
return success; return success;
...@@ -487,7 +490,12 @@ static int try_to_wake_up(task_t * p, int sync) ...@@ -487,7 +490,12 @@ static int try_to_wake_up(task_t * p, int sync)
int wake_up_process(task_t * p) int wake_up_process(task_t * p)
{ {
return try_to_wake_up(p, 0); return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0);
}
int wake_up_state(task_t *p, unsigned int state)
{
return try_to_wake_up(p, state, 0);
} }
/* /*
...@@ -1263,7 +1271,7 @@ asmlinkage void preempt_schedule(void) ...@@ -1263,7 +1271,7 @@ asmlinkage void preempt_schedule(void)
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 ((p->state & mode) && try_to_wake_up(p, sync)); return try_to_wake_up(p, mode, sync);
} }
/* /*
...@@ -2418,7 +2426,7 @@ void __init sched_init(void) ...@@ -2418,7 +2426,7 @@ void __init sched_init(void)
rq->curr = current; rq->curr = current;
rq->idle = current; rq->idle = current;
set_task_cpu(current, smp_processor_id()); set_task_cpu(current, smp_processor_id());
wake_up_process(current); wake_up_forked_process(current);
init_timers(); init_timers();
......
...@@ -620,13 +620,9 @@ static void handle_stop_signal(int sig, struct task_struct *p) ...@@ -620,13 +620,9 @@ static void handle_stop_signal(int sig, struct task_struct *p)
t = p; t = p;
do { do {
rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
wake_up_state(t, TASK_STOPPED);
/* /*
* This wakeup is only need if in TASK_STOPPED,
* but there can be SMP races with testing for that.
* In the normal SIGCONT case, all will be stopped.
* A spuriously sent SIGCONT will interrupt all running
* threads to check signals even if it's ignored.
*
* If there is a handler for SIGCONT, we must make * If there is a handler for SIGCONT, we must make
* sure that no thread returns to user mode before * sure that no thread returns to user mode before
* we post the signal, in case it was the only * we post the signal, in case it was the only
...@@ -637,11 +633,9 @@ static void handle_stop_signal(int sig, struct task_struct *p) ...@@ -637,11 +633,9 @@ static void handle_stop_signal(int sig, struct task_struct *p)
* siglock that we hold now and until we've queued * siglock that we hold now and until we've queued
* the pending signal. * the pending signal.
*/ */
if (!(t->flags & PF_EXITING)) {
if (!sigismember(&t->blocked, SIGCONT)) if (!sigismember(&t->blocked, SIGCONT))
set_tsk_thread_flag(t, TIF_SIGPENDING); set_tsk_thread_flag(t, TIF_SIGPENDING);
wake_up_process(t);
}
t = next_thread(t); t = next_thread(t);
} while (t != p); } while (t != p);
} }
......
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