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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Fri Sep 27 16:49:14 2013 +0200

cobalt/thread: serialize pthread_join() with Cobalt thread exit handler

This change addresses the following situation:

1. parent(high-prio) waits in pthread_join(child)
2. child(low-prio) enters exit path, unblocks parent
3. parent resumes, invokes Cobalt service for child

Normally, the parent would expect the child's thread_id to be invalid
upon return from pthread_join(). To guarantee this, we have to
serialize pthread_join() with the thread exit handler within the
Cobalt core, which actually dismisses the local thread identifier.

---

 include/cobalt/pthread.h      |    2 ++
 include/cobalt/uapi/syscall.h |    2 +-
 kernel/cobalt/posix/syscall.c |    1 +
 kernel/cobalt/posix/thread.c  |   35 ++++++++++++++++++++++++++++++++++-
 kernel/cobalt/posix/thread.h  |    8 ++++++--
 lib/cobalt/cobalt.wrappers    |    1 +
 lib/cobalt/thread.c           |   40 ++++++++++++++++++++++++++++++++++++++++
 lib/cobalt/wrappers.c         |    6 ++++++
 8 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/include/cobalt/pthread.h b/include/cobalt/pthread.h
index 881f5f7..84158f5 100644
--- a/include/cobalt/pthread.h
+++ b/include/cobalt/pthread.h
@@ -124,6 +124,8 @@ COBALT_DECL(int, pthread_cond_broadcast(pthread_cond_t 
*cond));
 
 COBALT_DECL(int, pthread_kill(pthread_t tid, int sig));
 
+COBALT_DECL(int, pthread_join(pthread_t tid, void **retval));
+
 COBALT_DECL(int, pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr,
                                               int *proto));
 
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index 3d92f29..ed60c35 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -93,7 +93,7 @@
 #define sc_cobalt_condattr_setclock     72
 #define sc_cobalt_condattr_getpshared   73
 #define sc_cobalt_condattr_setpshared   74
-/* 75 unimplemented */
+#define sc_cobalt_thread_join           75
 #define sc_cobalt_thread_kill           76
 #define sc_cobalt_select                77
 #define sc_cobalt_thread_setschedparam_ex      78
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 81ea80a..e3a135d 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -93,6 +93,7 @@ static struct xnsyscall cobalt_syscalls[] = {
        SKINCALL_DEF(sc_cobalt_thread_probe, cobalt_thread_probe_np, any),
        SKINCALL_DEF(sc_cobalt_thread_kill, cobalt_thread_kill, conforming),
        SKINCALL_DEF(sc_cobalt_thread_getstat, cobalt_thread_stat, any),
+       SKINCALL_DEF(sc_cobalt_thread_join, cobalt_thread_join, primary),
        SKINCALL_DEF(sc_cobalt_sem_init, cobalt_sem_init, any),
        SKINCALL_DEF(sc_cobalt_sem_destroy, cobalt_sem_destroy, any),
        SKINCALL_DEF(sc_cobalt_sem_post, cobalt_sem_post, any),
diff --git a/kernel/cobalt/posix/thread.c b/kernel/cobalt/posix/thread.c
index c2c4a24..61b09ae 100644
--- a/kernel/cobalt/posix/thread.c
+++ b/kernel/cobalt/posix/thread.c
@@ -240,6 +240,9 @@ struct xnpersonality *cobalt_thread_exit(struct xnthread 
*curr)
        cobalt_signal_flush(thread);
        xnsynch_destroy(&thread->monitor_synch);
        xnsynch_destroy(&thread->sigwait);
+       /* Waiters will receive EIDRM */
+       xnsynch_destroy(&thread->join_synch);
+       xnsched_run();
 
        return NULL;
 }
@@ -512,8 +515,9 @@ static inline int pthread_create(struct cobalt_thread 
**thread_p, const pthread_
 
        thread->hkey.u_pth = 0;
        thread->hkey.mm = NULL;
+       xnsynch_init(&thread->join_synch, XNSYNCH_FIFO, NULL);
 
-       *thread_p = thread; /* Must be done before the thread is started. */
+       *thread_p = thread;
 
        return 0;
 }
@@ -1099,6 +1103,35 @@ int cobalt_thread_kill(unsigned long pth, int sig)
        return ret;
 }
 
+int cobalt_thread_join(unsigned long pth)
+{
+       struct cobalt_local_hkey hkey;
+       struct cobalt_thread *thread;
+       int ret;
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
+
+       hkey.u_pth = pth;
+       hkey.mm = current->mm;
+       thread = thread_lookup(&hkey);
+       if (thread == NULL)
+               ret = -ESRCH;
+       else {
+               if (xnsynch_pended_p(&thread->join_synch))
+                       ret = -EBUSY;
+               else {
+                       ret = xnsynch_sleep_on(&thread->join_synch,
+                                              XN_INFINITE, XN_RELATIVE);
+                       ret = ret & XNBREAK ? -EINTR : 0;
+               }
+       }
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       return ret;
+}
+
 int cobalt_thread_stat(pid_t pid,
                       struct cobalt_threadstat __user *u_stat)
 {
diff --git a/kernel/cobalt/posix/thread.h b/kernel/cobalt/posix/thread.h
index 512aa60..60f2ef1 100644
--- a/kernel/cobalt/posix/thread.h
+++ b/kernel/cobalt/posix/thread.h
@@ -116,15 +116,17 @@ struct cobalt_thread {
        struct xnsynch sigwait;
        struct list_head signext;
 
-       /* Cached value for current policy (user side). */
+       /** Cached value for current policy (user side). */
        int sched_u_policy;
 
-       /* Monitor wait object and link holder. */
+       /** Monitor wait object and link holder. */
        struct xnsynch monitor_synch;
        struct list_head monitor_link;
        int monitor_queued;
 
        struct cobalt_local_hkey hkey;
+       /** Exit event for joining the thread. */
+       struct xnsynch join_synch;
 };
 
 struct cobalt_sigwait_context {
@@ -167,6 +169,8 @@ int cobalt_thread_probe_np(pid_t h_tid);
 
 int cobalt_thread_kill(unsigned long tid, int sig);
 
+int cobalt_thread_join(unsigned long tid);
+
 int cobalt_thread_stat(pid_t pid,
                       struct cobalt_threadstat __user *u_stat);
 
diff --git a/lib/cobalt/cobalt.wrappers b/lib/cobalt/cobalt.wrappers
index 5a16583..519973d 100644
--- a/lib/cobalt/cobalt.wrappers
+++ b/lib/cobalt/cobalt.wrappers
@@ -6,6 +6,7 @@
 --wrap sched_get_priority_min
 --wrap sched_get_priority_max
 --wrap pthread_kill
+--wrap pthread_join
 --wrap sem_init
 --wrap sem_destroy
 --wrap sem_post
diff --git a/lib/cobalt/thread.c b/lib/cobalt/thread.c
index c6db4b0..4165a23 100644
--- a/lib/cobalt/thread.c
+++ b/lib/cobalt/thread.c
@@ -447,6 +447,46 @@ COBALT_IMPL(int, pthread_kill, (pthread_t thread, int sig))
        return ret;
 }
 
+COBALT_IMPL(int, pthread_join, (pthread_t thread, void **retval))
+{
+       int ret;
+
+       ret = __STD(pthread_join(thread, retval));
+       if (ret)
+               return ret;
+
+       /*
+        * Serialize with the regular task exit path, so that no call
+        * for the joined pthread may succeed after this routine
+        * returns. A successful call to sc_cobalt_thread_join
+        * receives -EIDRM, meaning that we eventually joined the
+        * exiting thread as seen by the Cobalt core.
+        *
+        * -ESRCH means that the joined thread has already exited
+        * linux-wise, while we were about to wait for it from the
+        * Cobalt side, in which case we are fine.
+        *
+        * -EBUSY denotes a multiple join for several threads in
+        * parallel to the same target. We remap this error code to
+        * EINVAL to match the glibc. NOTE: we should not receive this
+        * error code, since the initial __STD() call should have
+        * returned EINVAL. This case is handled there mainly for
+        * documentation purpose.
+        *
+        * -EPERM may be received because the current context is not a
+        * Xenomai thread, in which case we simply ignore the error
+        * code.
+        *
+        * Zero is unexpected.
+        */
+       do
+               ret = -XENOMAI_SKINCALL1(__cobalt_muxid,
+                                        sc_cobalt_thread_join, thread);
+       while (ret == EINTR);
+
+       return ret == EBUSY ? EINVAL : 0;
+}
+
 static __attribute__((constructor)) void cobalt_thread_init(void)
 {
 #ifdef _CS_GNU_LIBPTHREAD_VERSION
diff --git a/lib/cobalt/wrappers.c b/lib/cobalt/wrappers.c
index 6247915..a4f643e 100644
--- a/lib/cobalt/wrappers.c
+++ b/lib/cobalt/wrappers.c
@@ -90,6 +90,12 @@ int __real_pthread_kill(pthread_t tid, int sig)
        return pthread_kill(tid, sig);
 }
 
+__attribute__ ((weak))
+int __real_pthread_join(pthread_t tid, void **retval)
+{
+       return pthread_join(tid, retval);
+}
+
 /* semaphores */
 __attribute__ ((weak))
 int __real_sem_init(sem_t * sem, int pshared, unsigned value)


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

Reply via email to