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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Jan  8 15:25:43 2013 +0100

nucleus/pod: introduce xnpod_thread_join()

This service waits for a cancelled thread to terminate, without polling.

---

 include/cobalt/nucleus/pod.h    |    2 +
 include/cobalt/nucleus/thread.h |    2 +-
 kernel/cobalt/nucleus/pod.c     |   66 +++++++++++++++++++++++++++++++++++++-
 kernel/cobalt/nucleus/shadow.c  |    3 --
 kernel/cobalt/nucleus/thread.c  |    3 ++
 5 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/include/cobalt/nucleus/pod.h b/include/cobalt/nucleus/pod.h
index 193d94f..685f970 100644
--- a/include/cobalt/nucleus/pod.h
+++ b/include/cobalt/nucleus/pod.h
@@ -198,6 +198,8 @@ void xnpod_testcancel_thread(void);
 
 void xnpod_cancel_thread(xnthread_t *thread);
 
+void xnpod_join_thread(xnthread_t *thread);
+
 xnflags_t xnpod_set_thread_mode(xnthread_t *thread,
                                xnflags_t clrmask,
                                xnflags_t setmask);
diff --git a/include/cobalt/nucleus/thread.h b/include/cobalt/nucleus/thread.h
index bfe561a..fa672a4 100644
--- a/include/cobalt/nucleus/thread.h
+++ b/include/cobalt/nucleus/thread.h
@@ -210,7 +210,7 @@ typedef struct xnthread {
        struct xnsched_sporadic_data *pss; /* Sporadic scheduling data. */
 #endif
 
-       unsigned idtag;                 /* Unique ID tag */
+       unsigned int idtag;     /* Unique ID tag */
 
        cpumask_t affinity;     /* Processor affinity. */
 
diff --git a/kernel/cobalt/nucleus/pod.c b/kernel/cobalt/nucleus/pod.c
index 5d36df4..d1a30d2 100644
--- a/kernel/cobalt/nucleus/pod.c
+++ b/kernel/cobalt/nucleus/pod.c
@@ -36,6 +36,7 @@
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
 #include <linux/sched.h>
+#include <linux/wait.h>
 #include <nucleus/version.h>
 #include <nucleus/pod.h>
 #include <nucleus/timer.h>
@@ -67,6 +68,8 @@ struct xnvfile_directory debug_vfroot;
 EXPORT_SYMBOL_GPL(debug_vfroot);
 #endif
 
+static DECLARE_WAIT_QUEUE_HEAD(nkjoinq);
+
 #ifdef CONFIG_XENO_HW_FPU
 
 static inline void __xnpod_giveup_fpu(struct xnsched *sched,
@@ -807,7 +810,7 @@ static inline int moving_target(struct xnsched *sched, 
struct xnthread *thread)
        return ret;
 }
 
-void __xnpod_cleanup_thread(struct xnthread *thread) /* nklock held, irqs off 
*/
+static void cleanup_thread(struct xnthread *thread) /* nklock held, irqs off */
 {
        struct xnsched *sched = thread->sched;
 
@@ -826,6 +829,7 @@ void __xnpod_cleanup_thread(struct xnthread *thread) /* 
nklock held, irqs off */
        xntimer_destroy(&thread->rtimer);
        xntimer_destroy(&thread->ptimer);
        xntimer_destroy(&thread->rrbtimer);
+       thread->idtag = 0;
 
        if (thread->selector) {
                xnselector_destroy(thread->selector);
@@ -856,6 +860,17 @@ void __xnpod_cleanup_thread(struct xnthread *thread) /* 
nklock held, irqs off */
        }
 }
 
+void __xnpod_cleanup_thread(struct xnthread *thread)
+{
+       spl_t s;
+
+       XENO_BUGON(NUCLEUS, !ipipe_root_p);
+       xnlock_get_irqsave(&nklock, s);
+       cleanup_thread(thread);
+       xnlock_put_irqrestore(&nklock, s);
+       wake_up(&nkjoinq);
+}
+
 /**
  * @fn void xnpod_testcancel_thread(void)
  *
@@ -924,7 +939,7 @@ void xnpod_cancel_thread(struct xnthread *thread)
        xnthread_set_info(thread, XNCANCELD);
 
        if (xnthread_test_state(thread, XNDORMANT)) {
-               __xnpod_cleanup_thread(thread);
+               cleanup_thread(thread);
                goto unlock_and_exit;
        }
 
@@ -943,6 +958,53 @@ unlock_and_exit:
 }
 EXPORT_SYMBOL_GPL(xnpod_cancel_thread);
 
+/**
+ * @fn void xnpod_join_thread(struct xnthread *thread)
+ *
+ * @brief Join with a terminated thread.
+ *
+ * This service waits for @a thread to terminate after a call to
+ * xnpod_cancel_thread().  If that thread has already terminated or is
+ * dormant at the time of the call, then xnpod_join_thread() returns
+ * immediately.
+ *
+ * @param thread The descriptor address of the thread to join with.
+ *
+ * Calling context: This service may be called from secondary mode
+ * only.
+ *
+ * Rescheduling: always if @a thread did not terminate yet at the time
+ * of the call.
+ */
+void xnpod_join_thread(struct xnthread *thread)
+{
+       unsigned int tag;
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
+
+       tag = thread->idtag;
+       if (xnthread_test_info(thread, XNDORMANT) || tag == 0) {
+               xnlock_put_irqrestore(&nklock, s);
+               return;
+       }
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       trace_mark(xn_nucleus, thread_join, "thread %p thread_name %s",
+                  thread, xnthread_name(thread));
+
+       /*
+        * Only a very few threads are likely to terminate within a
+        * short time frame at any point in time, so experiencing a
+        * thundering herd effect due to synchronizing on a single
+        * wait queue is quite unlikely. In any case, we run in
+        * secondary mode.
+        */
+       wait_event(nkjoinq, thread->idtag != tag);
+}
+EXPORT_SYMBOL_GPL(xnpod_join_thread);
+
 /*!
  * \fn void xnpod_suspend_thread(xnthread_t *thread, xnflags_t mask,
  *                               xnticks_t timeout, xntmode_t timeout_mode,
diff --git a/kernel/cobalt/nucleus/shadow.c b/kernel/cobalt/nucleus/shadow.c
index 274c664..33d3e9e 100644
--- a/kernel/cobalt/nucleus/shadow.c
+++ b/kernel/cobalt/nucleus/shadow.c
@@ -2159,11 +2159,8 @@ static int handle_taskexit_event(struct task_struct *p) 
/* p == current */
        if (xnthread_test_state(thread, XNDEBUG))
                unlock_timers();
 
-       xnlock_get_irqsave(&nklock, s);
        /* __xnpod_cleanup_thread() -> hook -> xnshadow_unmap() */
        __xnpod_cleanup_thread(thread);
-       xnlock_put_irqrestore(&nklock, s);
-
        destroy_threadinfo();
 
        if (xnthread_test_state(thread, XNUSER)) {
diff --git a/kernel/cobalt/nucleus/thread.c b/kernel/cobalt/nucleus/thread.c
index 38918a6..ef905f1 100644
--- a/kernel/cobalt/nucleus/thread.c
+++ b/kernel/cobalt/nucleus/thread.c
@@ -120,6 +120,7 @@ int xnthread_init(struct xnthread *thread,
 {
        DECLARE_COMPLETION_ONSTACK(done);
        xnflags_t flags = attr->flags;
+       spl_t s;
        int ret;
 
        flags &= ~XNSUSP;
@@ -129,7 +130,9 @@ int xnthread_init(struct xnthread *thread,
        if (flags & XNROOT)
                thread->idtag = 0;
        else {
+               xnlock_get_irqsave(&nklock, s);
                thread->idtag = ++idtags ?: 1;
+               xnlock_put_irqrestore(&nklock, s);
                flags |= XNDORMANT;
        }
 


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to