Module: xenomai-jki
Branch: for-upstream
Commit: 0352b068600bd4ef3172c8a42416badbcdad32ca
URL:    
http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=0352b068600bd4ef3172c8a42416badbcdad32ca

Author: Jan Kiszka <jan.kis...@siemens.com>
Date:   Wed Apr 28 15:08:11 2010 +0200

native: Rework handling of pthread carrier thread

This patch improves two pitfalls of libnative's interaction with
underlying pthreads:

First, it tries to detect double deletions (cancellations or joinings)
of pthreads and report them via an error code. This reduces the risk to
trigger a SIGSEGV accessing meanwhile released pthread objects. And
second, it properly detaches joinable pthreads when they are deleted
instead. This properly releases the pthread resources.

To realize this, the patch uses the two topmost bits of the thread
handle to mark the states 'joinable' and 'deleted'. Those bits are
expected to be unable both for pointer-based as well as indexed thread
handles.

At this chance, canonicalize error codes (ESRCH -> EIDRM) and update the
documentation, specifically to clarify that rt_task_join must not be
combined with rt_task_delete.

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>

---

 ksrc/skins/native/task.c |   19 +++++++++++++++----
 src/skins/native/task.c  |   43 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/ksrc/skins/native/task.c b/ksrc/skins/native/task.c
index 6d2472e..408c62b 100644
--- a/ksrc/skins/native/task.c
+++ b/ksrc/skins/native/task.c
@@ -588,6 +588,9 @@ int rt_task_resume(RT_TASK *task)
  *
  * Rescheduling: always if @a task is NULL, and possible if the
  * deleted task is currently running into a safe section.
+ *
+ * @note A task that was successfully joined via rt_task_join() must not be
+ * explicitly deleted afterwards.
  */
 
 int rt_task_delete(RT_TASK *task)
@@ -2407,23 +2410,31 @@ int rt_task_reply(int flowid, RT_TASK_MCB *mcb_s)
  * @brief Wait on the termination of a real-time task.
  *
  * This user-space only service blocks the caller in non-real-time context
- * until @a task has terminated. Note that the specified task must have
- * been created with the T_JOINABLE mode flag set.
+ * until @a task has terminated. All real-time kernel resources are released
+ * on successful completion of this service. Note that the specified task must
+ * have been created with the T_JOINABLE mode flag set by the same process
+ * that wants to join it.
  *
  * @param task The address of a task descriptor to join.
  *
  * @return 0 is returned upon success. Otherwise:
  *
- * - -EINVAL is returned if the task was not created with T_JOINABLE set or
- * some other task is already waiting on the termination.
+ * - -EINVAL is returned if the task was not created with T_JOINABLE set,
+ * some other task is already waiting on the termination, or the task was
+ * originally created by a different process.
  *
  * - -EDEADLK is returned if @a task refers to the caller.
  *
+ * - -EIDRM is returned if @a task is a deleted task descriptor.
+ *
  * This service can be called from:
  *
  * - User-space task.
  *
  * Rescheduling: always unless the task was already terminated.
+ *
+ * @note After successful completion of this service it is neither required
+ * nor valid to additionally invoke rt_task_delete() on the same task.
  */
 
 /**
diff --git a/src/skins/native/task.c b/src/skins/native/task.c
index d975508..ec8c684 100644
--- a/src/skins/native/task.c
+++ b/src/skins/native/task.c
@@ -31,6 +31,11 @@
 #include <asm-generic/stack.h>
 #include "wrappers.h"
 
+#define BITS_OF_PTHREAD                        (sizeof(pthread_t) * 8)
+#define RT_TASK_PTHREAD_JOINABLE       (1UL << (BITS_OF_PTHREAD - 2))
+#define RT_TASK_PTHREAD_DELETED                (2UL << (BITS_OF_PTHREAD - 2))
+#define RT_TASK_PTHREAD_MASK           (~(3UL << (BITS_OF_PTHREAD - 2)))
+
 #ifdef HAVE___THREAD
 __thread RT_TASK __native_self __attribute__ ((tls_model ("initial-exec"))) = {
        .opaque = XN_NO_HANDLE,
@@ -44,6 +49,11 @@ extern int __native_muxid;
 
 /* Public Xenomai interface. */
 
+static inline pthread_t rt_task_to_pthread(RT_TASK *task)
+{
+       return (pthread_t)(task->opaque2 & RT_TASK_PTHREAD_MASK);
+}
+
 struct rt_task_iargs {
        RT_TASK *task;
        const char *name;
@@ -78,6 +88,8 @@ static void *rt_task_trampoline(void *cookie)
        bulk.a3 = (u_long)iargs->prio;
        bulk.a4 = (u_long)iargs->mode;
        bulk.a5 = (u_long)pthread_self();
+       if (iargs->mode & T_JOINABLE)
+               bulk.a5 |= RT_TASK_PTHREAD_JOINABLE;
        /* Signal allocation failures by setting bulk.a6 to 0, they will be
           propagated to the thread waiting in xn_sys_completion. */
        bulk.a6 = !self ? 0UL : (u_long)xeno_init_current_mode();
@@ -211,6 +223,8 @@ int rt_task_shadow(RT_TASK *task, const char *name, int 
prio, int mode)
        bulk.a3 = (u_long)prio;
        bulk.a4 = (u_long)mode;
        bulk.a5 = (u_long)pthread_self();
+       if (mode & T_JOINABLE)
+               bulk.a5 |= RT_TASK_PTHREAD_JOINABLE;
        bulk.a6 = (u_long)xeno_init_current_mode();
 
        if (!bulk.a6) {
@@ -266,9 +280,17 @@ int rt_task_delete(RT_TASK *task)
        }
 
        if (task->opaque2) {
-               err = pthread_cancel((pthread_t)task->opaque2);
-               if (err)
-                       return -err;
+               if ((task->opaque2 & RT_TASK_PTHREAD_DELETED) ||
+                   pthread_cancel(rt_task_to_pthread(task)))
+                       return -EIDRM;
+
+               if (task->opaque2 & RT_TASK_PTHREAD_JOINABLE) {
+                       err = pthread_detach(rt_task_to_pthread(task));
+                       if (err)
+                               return -err;
+               }
+
+               task->opaque2 = RT_TASK_PTHREAD_DELETED;
        }
 
        err = XENOMAI_SKINCALL1(__native_muxid, __native_task_delete, task);
@@ -367,10 +389,19 @@ int rt_task_slice(RT_TASK *task, RTIME quantum)
 
 int rt_task_join(RT_TASK *task)
 {
-       if (!task->opaque2)
-               return -ESRCH;
+       int err;
+
+       if (task->opaque2 & RT_TASK_PTHREAD_DELETED)
+               return -EIDRM;
+       if (!(task->opaque2 & RT_TASK_PTHREAD_JOINABLE))
+               return -EINVAL;
+
+       err = -pthread_join(rt_task_to_pthread(task), NULL);
+
+       if (!err)
+               task->opaque2 = RT_TASK_PTHREAD_DELETED;
 
-       return -pthread_join((pthread_t)task->opaque2, NULL);
+       return (err == -ESRCH) ? -EIDRM : err;
 }
 
 ssize_t rt_task_send(RT_TASK *task,


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to