Module: xenomai-jki Branch: for-upstream Commit: 8c2cdb6e586d69eaf06c176645c7665d8b79bb4c URL: http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=8c2cdb6e586d69eaf06c176645c7665d8b79bb4c
Author: Jan Kiszka <jan.kis...@siemens.com> Date: Fri Jul 8 18:19:09 2011 +0200 nucleus: Fix race between gatekeeper and task signal wakeup As we cannot synchronize with Linux try_to_wake_up directly while it checks if a hijacked task may be woken up, take nklock while setting TASK_ATOMICSWITCH and check for pending signals beforehand. This also removes any valid reason to return from schedule in xnshadow_harden without being migrated. Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- ksrc/nucleus/shadow.c | 45 +++++++++++++++++++++++++++------------------ 1 files changed, 27 insertions(+), 18 deletions(-) diff --git a/ksrc/nucleus/shadow.c b/ksrc/nucleus/shadow.c index 235209d..1030817 100644 --- a/ksrc/nucleus/shadow.c +++ b/ksrc/nucleus/shadow.c @@ -941,6 +941,7 @@ int xnshadow_harden(void) struct xnthread *thread; struct xnsched *sched; int cpu; + spl_t s; redo: thread = xnshadow_thread(this_task); @@ -950,8 +951,8 @@ redo: cpu = task_cpu(this_task); sched = xnpod_sched_slot(cpu); - if (signal_pending(this_task) || down_interruptible(&sched->gksync)) - /* Grab the request token. */ + /* Grab the request token. */ + if (down_interruptible(&sched->gksync)) return -ERESTARTSYS; if (thread->u_mode) @@ -985,32 +986,40 @@ redo: "thread %p thread_name %s comm %s", thread, xnthread_name(thread), this_task->comm); + xnlock_get_irqsave(&nklock, s); + + /* + * Recheck if there are no signals pending. We must not start the + * migration as in that case both Linux and the gatekeeper may resume + * the same task. + * + * TASK_ATOMICSWITCH is tested by try_to_wake_up under rq lock, but + * that is not available to us. Holding nklock synchronizes us with + * do_sigwake_event to ensure the ATOMICSWITCH will be visible for + * try_to_wake_up when we proceed. + */ + if (signal_pending(this_task)) { + xnlock_put_irqrestore(&nklock, s); + + preempt_enable(); + up(&sched->gksync); + + return -ERESTARTSYS; + } + sched->gktarget = thread; thread->gksched = sched; xnthread_set_info(thread, XNATOMIC); set_current_state(TASK_INTERRUPTIBLE | TASK_ATOMICSWITCH); + xnlock_put_irqrestore(&nklock, s); + wake_up_process(sched->gatekeeper); schedule(); xnthread_clear_info(thread, XNATOMIC); - /* - * Rare case: we might have been awaken by a signal before the - * gatekeeper sent us to primary mode. Since - * TASK_UNINTERRUPTIBLE is unavailable to us without wrecking - * the runqueue's count of uniniterruptible tasks, we just - * notice the issue and gracefully fail; the caller will have - * to process this signal anyway. - */ - if (rthal_current_domain == rthal_root_domain) { - if (XENO_DEBUG(NUCLEUS) && (!signal_pending(this_task) - || this_task->state != TASK_RUNNING)) - xnpod_fatal - ("xnshadow_harden() failed for thread %s[%d]", - thread->name, xnthread_user_pid(thread)); - return -ERESTARTSYS; - } + XENO_BUGON(NUCLEUS, rthal_current_domain == rthal_root_domain); /* "current" is now running into the Xenomai domain. */ sched = xnsched_finish_unlocked_switch(thread->sched); _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git