Module: xenomai-forge Branch: next Commit: 7c333b78a809b78f72bfc07d05f9236a182a2b82 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=7c333b78a809b78f72bfc07d05f9236a182a2b82
Author: Philippe Gerum <r...@xenomai.org> Date: Thu May 8 13:09:20 2014 +0200 cobalt/thread: fix leakage of XNKICKED status Considering the following scenario, on a multi-core system: 1. kernel@CPU0 sends regular linux signal to preempted thread@CPU1 2. thread@CPU1 kicked in ready state (XNREADY|XNKICKED) in sigwake 3. thread@CPU1 regains CPU, invokes linux/lostage syscall next 4. thread@CPU1 relaxes prior to running syscall handler 5. thread@CPU1 skips prepare_for_signal() because in relaxed mode 6. thread@CPU1 handles regular signal on its way back to userland => XNKICKED set, signal_pending(thread) cleared. 7. thread@CPU1 invokes syscall requiring primary mode (hardens at first pass) 8. thread@CPU1 runs blocking Xenomai syscall, fails due to XNKICKED 9. thread@CPU1 skips prepare_for_signal() because signal_pending() false 10. goto 7 Oops. The fix is to make sure that a kicked thread about to relax (which means suspend Xenomai-wise) clears the XNKICKED bit right before suspending, since it will necessarily traverse the regular signal handling code on its way back to userland, prior to returning from a blocking Xenomai service. --- kernel/cobalt/thread.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c index 7e4c9de..5887be9 100644 --- a/kernel/cobalt/thread.c +++ b/kernel/cobalt/thread.c @@ -810,18 +810,16 @@ void xnthread_suspend(struct xnthread *thread, int mask, /* * If attempting to suspend a runnable thread which is pending - * a forced switch to secondary mode, just raise the break - * condition and return immediately. + * a forced switch to secondary mode (XNKICKED), just raise + * the XNBREAK status and return immediately, except if we + * are precisely doing such switch by applying XNRELAX. * - * We may end up suspending a kicked thread that has been - * preempted on its relaxing path, which is a perfectly valid - * situation: we just ignore the signal notification in - * primary mode, and rely on the wakeup call pending for that - * task in the root context, to collect and act upon the - * pending Linux signal (see handle_sigwake_event()). + * In the latter case, we also make sure to clear XNKICKED, + * since we won't go through prepare_for_signal() once + * relaxed. */ - if ((oldstate & XNTHREAD_BLOCK_BITS) == 0) { - if ((mask & XNRELAX) == 0) { + if (likely((oldstate & XNTHREAD_BLOCK_BITS) == 0)) { + if (likely((mask & XNRELAX) == 0)) { if (xnthread_test_info(thread, XNKICKED)) goto abort; if (thread == sched->curr && @@ -829,7 +827,7 @@ void xnthread_suspend(struct xnthread *thread, int mask, goto abort; } xnthread_clear_info(thread, - XNRMID|XNTIMEO|XNBREAK|XNWAKEN|XNROBBED); + XNRMID|XNTIMEO|XNBREAK|XNWAKEN|XNROBBED|XNKICKED); } /* _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git