Module: xenomai-forge
Branch: next
Commit: cac9859c1adea74f3fea3ce6b52588c616048f39
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=cac9859c1adea74f3fea3ce6b52588c616048f39

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

Reply via email to