]> git.hungrycats.org Git - linux/commitdiff
[PATCH] SMP signal latency fix
authorIngo Molnar <mingo@elte.hu>
Sat, 8 Nov 2003 08:06:19 +0000 (00:06 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Sat, 8 Nov 2003 08:06:19 +0000 (00:06 -0800)
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.

include/linux/sched.h
kernel/sched.c
kernel/signal.c

index 031579e7e3fc5d44f2314e5833b0e349fda5e707..fbf3c753ef8a10baddc04dc97f9db1fb09d27975 100644 (file)
@@ -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_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(sched_exit(task_t * p));
 
index f4e5d8e04b9cde48c1a8af00fe7c1ba6685ef583..e99231d2429d0d80260c83cfa018d24e071ed03d 100644 (file)
@@ -530,6 +530,15 @@ static inline void resched_task(task_t *p)
 #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
 
 /*
@@ -568,6 +577,27 @@ repeat:
        task_rq_unlock(rq, &flags);
        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
 
 /***
@@ -575,7 +605,6 @@ repeat:
  * @p: the to-be-woken-up thread
  * @state: the mask of task states that can be woken
  * @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"
  * thread is always on the run-queue (except when the actual
@@ -585,7 +614,7 @@ repeat:
  *
  * 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;
        int success = 0;
@@ -626,33 +655,22 @@ repeat_lock_task:
                        }
                        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;
        }
        task_rq_unlock(rq, &flags);
 
        return success;
 }
-
 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);
 
-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)
 {
-       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);
 int default_wake_function(wait_queue_t *curr, unsigned mode, int sync)
 {
        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);
@@ -1941,15 +1959,6 @@ int task_nice(task_t *p)
 
 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?
  * @cpu: the processor in question.
index 852da1a009dab94739aba3242b9af1524c8bea8f..150062afd23310a0e56126048ea2189a5095b99a 100644 (file)
@@ -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)
 {
        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.
@@ -551,10 +552,11 @@ inline void signal_wake_up(struct task_struct *t, int resume)
        mask = TASK_INTERRUPTIBLE;
        if (resume)
                mask |= TASK_STOPPED;
-       if (t->state & mask) {
-               wake_up_process_kick(t);
-               return;
-       }
+       woken = 0;
+       if (t->state & mask)
+               woken = wake_up_state(t, mask);
+       if (!woken)
+               kick_process(t);
 }
 
 /*