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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Sun Feb  9 17:06:08 2014 +0100

copperplate/internal: add parent-child handshake protocol at spawn

We want to provide the ability to run a prologue code on behalf of the
emerging child context, which the parent shall wait for completion of
before continuing.

This feature can be used to guarantee that a child thread has
performed a set of actions before the caller of
copperplate_create_thread() is allowed to refer to it.

---

 lib/alchemy/task.c         |   42 ++++++++------
 lib/copperplate/internal.c |  132 ++++++++++++++++++++++++++++++++++++++++++--
 lib/copperplate/internal.h |   13 ++++-
 lib/copperplate/timerobj.c |   37 ++++---------
 lib/psos/task.c            |   20 +++----
 lib/vxworks/taskLib.c      |   20 ++++---
 6 files changed, 193 insertions(+), 71 deletions(-)

diff --git a/lib/alchemy/task.c b/lib/alchemy/task.c
index 4f2a90c..38aaf18 100644
--- a/lib/alchemy/task.c
+++ b/lib/alchemy/task.c
@@ -143,17 +143,18 @@ static void task_finalizer(struct threadobj *thobj)
        syncobj_destroy(&tcb->sobj_msg, &syns);
 }
 
-static int task_prologue(struct alchemy_task *tcb)
+static int task_prologue_1(void *arg)
+{
+       struct alchemy_task *tcb = arg;
+
+       return __bt(threadobj_prologue(&tcb->thobj, tcb->name));
+}
+
+static int task_prologue_2(struct alchemy_task *tcb)
 {
        struct service svc;
        int ret;
 
-       ret = __bt(threadobj_prologue(&tcb->thobj, tcb->name));
-       if (ret) {
-               backtrace_check();
-               return ret;
-       }
-
        CANCEL_DEFER(svc);
 
        threadobj_wait_start();
@@ -167,23 +168,22 @@ static int task_prologue(struct alchemy_task *tcb)
        return ret;
 }
 
-static void *task_trampoline(void *arg)
+static void *task_entry(void *arg)
 {
        struct alchemy_task *tcb = arg;
        int ret;
 
-       ret = task_prologue(tcb);
+       ret = __bt(task_prologue_2(tcb));
        if (ret)
-               goto out;
+               return (void *)(long)ret;
 
        threadobj_notify_entry();
        tcb->entry(tcb->arg);
-out:
        threadobj_lock(&tcb->thobj);
        threadobj_set_magic(&tcb->thobj, ~task_magic);
        threadobj_unlock(&tcb->thobj);
 
-       pthread_exit((void *)(long)ret);
+       return NULL;
 }
 
 static void delete_tcb(struct alchemy_task *tcb)
@@ -354,7 +354,8 @@ int rt_task_create(RT_TASK *task, const char *name,
        cta.detachstate = mode & T_JOINABLE ?
                PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED;
        cta.prio = prio;
-       cta.start = task_trampoline;
+       cta.prologue = task_prologue_1;
+       cta.run = task_entry;
        cta.arg = tcb;
        cta.stacksize = stksize;
 
@@ -676,11 +677,13 @@ int rt_task_shadow(RT_TASK *task, const char *name, int 
prio, int mode)
 
        threadobj_shadow(&tcb->thobj);  /* We won't wait in prologue. */
 
-       ret = task_prologue(tcb);
-       if (ret) {
-               delete_tcb(tcb);
-               goto out;
-       }
+       ret = threadobj_prologue(&tcb->thobj, tcb->name);
+       if (ret)
+               goto undo;
+
+       ret = task_prologue_2(tcb);
+       if (ret)
+               goto undo;
 
        self = pthread_self();
        if (task)
@@ -691,6 +694,9 @@ out:
        CANCEL_RESTORE(svc);
 
        return ret;
+undo:
+       delete_tcb(tcb);
+       goto out;
 }
 
 /**
diff --git a/lib/copperplate/internal.c b/lib/copperplate/internal.c
index dc49861..0b4b653 100644
--- a/lib/copperplate/internal.c
+++ b/lib/copperplate/internal.c
@@ -26,11 +26,18 @@
 #include <errno.h>
 #include <limits.h>
 #include <linux/unistd.h>
+#include <boilerplate/ancillaries.h>
 #include <copperplate/clockobj.h>
 #include <copperplate/threadobj.h>
 #include <copperplate/init.h>
 #include "internal.h"
 
+static int thread_spawn_prologue(struct corethread_attributes *cta);
+
+static int thread_spawn_epilogue(struct corethread_attributes *cta);
+
+static void *thread_trampoline(void *arg);
+
 pid_t copperplate_get_tid(void)
 {
        /*
@@ -43,6 +50,8 @@ pid_t copperplate_get_tid(void)
 
 #ifdef CONFIG_XENO_COBALT
 
+#include "cobalt/internal.h"
+
 int copperplate_probe_node(unsigned int id)
 {
        /*
@@ -56,7 +65,7 @@ int copperplate_probe_node(unsigned int id)
        return pthread_probe_np((pid_t)id) == 0;
 }
 
-int copperplate_create_thread(const struct corethread_attributes *cta,
+int copperplate_create_thread(struct corethread_attributes *cta,
                              pthread_t *tid)
 {
        struct sched_param_ex param_ex;
@@ -64,6 +73,10 @@ int copperplate_create_thread(const struct 
corethread_attributes *cta,
        size_t stacksize;
        int policy, ret;
 
+       ret = thread_spawn_prologue(cta);
+       if (ret)
+               return __bt(ret);
+
        stacksize = cta->stacksize;
        if (stacksize < PTHREAD_STACK_MIN * 4)
                stacksize = PTHREAD_STACK_MIN * 4;
@@ -76,10 +89,15 @@ int copperplate_create_thread(const struct 
corethread_attributes *cta,
        pthread_attr_setschedparam_ex(&attr_ex, &param_ex);
        pthread_attr_setstacksize_ex(&attr_ex, stacksize);
        pthread_attr_setdetachstate_ex(&attr_ex, cta->detachstate);
-       ret = __bt(-pthread_create_ex(tid, &attr_ex, cta->start, cta->arg));
+       ret = __bt(-pthread_create_ex(tid, &attr_ex, thread_trampoline, cta));
        pthread_attr_destroy_ex(&attr_ex);
 
-       return ret;
+       if (ret)
+               return __bt(ret);
+
+       thread_spawn_epilogue(cta);
+
+       return 0;
 }
 
 int copperplate_renice_thread(pthread_t tid, int prio)
@@ -93,6 +111,18 @@ int copperplate_renice_thread(pthread_t tid, int prio)
        return __bt(-pthread_setschedparam_ex(tid, policy, &param_ex));
 }
 
+static inline void prepare_wait_corespec(void)
+{
+       /*
+        * Switch back to primary mode eagerly, so that both the
+        * parent and the child threads compete on the same priority
+        * scale when handshaking. In addition, this ensures the child
+        * thread enters the run() handler over the Xenomai domain,
+        * which is a basic assumption for all clients.
+        */
+       __cobalt_thread_harden();
+}
+
 #else /* CONFIG_XENO_MERCURY */
 
 int copperplate_probe_node(unsigned int id)
@@ -100,7 +130,7 @@ int copperplate_probe_node(unsigned int id)
        return kill((pid_t)id, 0) == 0;
 }
 
-int copperplate_create_thread(const struct corethread_attributes *cta,
+int copperplate_create_thread(struct corethread_attributes *cta,
                              pthread_t *tid)
 {
        struct sched_param param;
@@ -108,6 +138,10 @@ int copperplate_create_thread(const struct 
corethread_attributes *cta,
        size_t stacksize;
        int policy, ret;
 
+       ret = thread_spawn_prologue(cta);
+       if (ret)
+               return __bt(ret);
+
        stacksize = cta->stacksize;
        if (stacksize < PTHREAD_STACK_MIN * 4)
                stacksize = PTHREAD_STACK_MIN * 4;
@@ -120,10 +154,15 @@ int copperplate_create_thread(const struct 
corethread_attributes *cta,
        pthread_attr_setschedparam(&attr, &param);
        pthread_attr_setstacksize(&attr, stacksize);
        pthread_attr_setdetachstate(&attr, cta->detachstate);
-       ret = __bt(-pthread_create(tid, &attr, cta->start, cta->arg));
+       ret = __bt(-pthread_create(tid, &attr, thread_trampoline, cta));
        pthread_attr_destroy(&attr);
 
-       return ret;
+       if (ret)
+               return __bt(ret);
+
+       ret = thread_spawn_epilogue(cta);
+
+       return __bt(ret);
 }
 
 int copperplate_renice_thread(pthread_t tid, int prio)
@@ -137,8 +176,89 @@ int copperplate_renice_thread(pthread_t tid, int prio)
        return __bt(-__RT(pthread_setschedparam(tid, policy, &param)));
 }
 
+static inline void prepare_wait_corespec(void)
+{
+       /* empty */
+}
+
 #endif  /* CONFIG_XENO_MERCURY */
 
+static int thread_spawn_prologue(struct corethread_attributes *cta)
+{
+       int ret;
+
+       ret = __RT(sem_init(&cta->__reserved.warm, 0, 0));
+       if (ret)
+               return __bt(ret);
+
+       cta->__reserved.status = -ENOSYS;
+
+       return 0;
+}
+
+static void thread_spawn_wait(sem_t *sem)
+{
+       int ret;
+
+       prepare_wait_corespec();
+
+       for (;;) {
+               ret = __RT(sem_wait(sem));
+               if (ret && errno == EINTR)
+                       continue;
+               if (ret == 0)
+                       return;
+               ret = -errno;
+               panic("sem_wait() failed with %s", symerror(ret));
+       }
+}
+
+static void *thread_trampoline(void *arg)
+{
+       struct corethread_attributes *cta = arg;
+       void *__arg, *(*__run)(void *arg);
+       sem_t released;
+       int ret;
+
+       /*
+        * cta may be on the parent's stack, so it may be dandling
+        * soon after the parent is posted: copy what we need from
+        * this area early on.
+        */
+       __run = cta->run;
+       __arg = cta->arg;
+       ret = cta->prologue(__arg);
+       cta->__reserved.status = ret;
+
+       if (ret) {
+               backtrace_check();
+               __RT(sem_post(&cta->__reserved.warm));
+               return (void *)(long)ret;
+       }
+
+       __RT(sem_init(&released, 0, 0));
+       cta->__reserved.released = &released;
+       __RT(sem_post(&cta->__reserved.warm));
+
+       thread_spawn_wait(&released);
+
+       __RT(sem_destroy(&released));
+
+       return __run(__arg);
+}
+
+static int thread_spawn_epilogue(struct corethread_attributes *cta)
+{
+       thread_spawn_wait(&cta->__reserved.warm);
+
+       if (cta->__reserved.status == 0)
+               __RT(sem_post(cta->__reserved.released));
+
+       __RT(sem_destroy(&cta->__reserved.warm));
+
+       return __bt(cta->__reserved.status);
+}
+
 void panic(const char *fmt, ...)
 {
        struct threadobj *thobj = threadobj_current();
diff --git a/lib/copperplate/internal.h b/lib/copperplate/internal.h
index 7909f39..e56a3bd 100644
--- a/lib/copperplate/internal.h
+++ b/lib/copperplate/internal.h
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 #include <time.h>
 #include <pthread.h>
+#include <semaphore.h>
 #include <sched.h>
 #include <xeno_config.h>
 #include <boilerplate/list.h>
@@ -55,10 +56,16 @@ struct shared_heap {
 
 struct corethread_attributes {
        int prio;
-       void *(*start)(void *arg);
-       void *arg;
        size_t stacksize;
        int detachstate;
+       int (*prologue)(void *arg);
+       void *(*run)(void *arg);
+       void *arg;
+       struct {
+               int status;
+               sem_t warm;
+               sem_t *released;
+       } __reserved;
 };
 
 extern pid_t __node_id;
@@ -71,7 +78,7 @@ pid_t copperplate_get_tid(void);
 
 int copperplate_probe_node(unsigned int id);
 
-int copperplate_create_thread(const struct corethread_attributes *cta,
+int copperplate_create_thread(struct corethread_attributes *cta,
                              pthread_t *tid);
 
 int copperplate_renice_thread(pthread_t tid, int prio);
diff --git a/lib/copperplate/timerobj.c b/lib/copperplate/timerobj.c
index 3dc7035..0e40577 100644
--- a/lib/copperplate/timerobj.c
+++ b/lib/copperplate/timerobj.c
@@ -35,8 +35,6 @@
 #include "copperplate/debug.h"
 #include "internal.h"
 
-static sem_t svsync;
-
 static pthread_mutex_t svlock;
 
 static pthread_t svthread;
@@ -95,6 +93,15 @@ static void timerobj_enqueue(struct timerobj *tmobj)
        atpvh(&__tmobj->next, &tmobj->next);
 }
 
+static int server_prologue(void *arg)
+{
+       svpid = copperplate_get_tid();
+       timersv_init_corespec("timer-internal");
+       threadobj_set_current(THREADOBJ_IRQCONTEXT);
+
+       return 0;
+}
+
 static void *timerobj_server(void *arg)
 {
        struct timespec now, value, interval;
@@ -102,15 +109,9 @@ static void *timerobj_server(void *arg)
        sigset_t set;
        int sig, ret;
 
-       svpid = copperplate_get_tid();
-       timersv_init_corespec("timer-internal");
-       threadobj_set_current(THREADOBJ_IRQCONTEXT);
        sigemptyset(&set);
        sigaddset(&set, SIGALRM);
 
-       /* Handshake with timerobj_spawn_server(). */
-       __RT(sem_post(&svsync));
-
        for (;;) {
                ret = __RT(sigwait(&set, &sig));
                if (ret && ret != -EINTR)
@@ -157,18 +158,12 @@ static int timerobj_spawn_server(void)
                goto out;
 
        cta.prio = threadobj_irq_prio;
-       cta.start = timerobj_server;
+       cta.prologue = server_prologue;
+       cta.run = timerobj_server;
        cta.arg = NULL;
        cta.stacksize = PTHREAD_STACK_MIN * 16;
        cta.detachstate = PTHREAD_CREATE_DETACHED;
        ret = __bt(copperplate_create_thread(&cta, &svthread));
-       if (ret)
-               return ret;
-
-       /* Wait for timer server to initialize. */
-       do
-               ret  = -__RT(sem_wait(&svsync));
-       while (ret == -EINTR);
 out:
        write_unlock(&svlock);
        pop_cleanup_lock(&svlock);
@@ -284,20 +279,12 @@ int timerobj_pkg_init(void)
        pthread_mutexattr_t mattr;
        int ret;
 
-       ret = __RT(sem_init(&svsync, 0, 0));
-       if (ret)
-               return __bt(-errno);
-
        __RT(pthread_mutexattr_init(&mattr));
        __RT(pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT));
        __RT(pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE));
        __RT(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE));
        ret = __RT(pthread_mutex_init(&svlock, &mattr));
        __RT(pthread_mutexattr_destroy(&mattr));
-       if (ret) {
-               __RT(sem_destroy(&svsync));
-               return __bt(-ret);
-       }
 
-       return 0;
+       return __bt(-ret);
 }
diff --git a/lib/psos/task.c b/lib/psos/task.c
index 393dfaf..25ab638 100644
--- a/lib/psos/task.c
+++ b/lib/psos/task.c
@@ -169,18 +169,18 @@ static void task_finalizer(struct threadobj *thobj)
        syncobj_destroy(&task->sobj, &syns);
 }
 
+static int task_prologue(void *arg)
+{
+       struct psos_task *task = arg;
+
+       return __bt(threadobj_prologue(&task->thobj, task->name));
+}
+
 static void *task_trampoline(void *arg)
 {
        struct psos_task *task = arg;
        struct psos_task_args *args = &task->args;
        struct service svc;
-       int ret;
-
-       ret = __bt(threadobj_prologue(&task->thobj, task->name));
-       if (ret) {
-               backtrace_check();
-               goto done;
-       }
 
        CANCEL_DEFER(svc);
 
@@ -200,12 +200,11 @@ static void *task_trampoline(void *arg)
 
        threadobj_notify_entry();
        args->entry(args->arg0, args->arg1, args->arg2, args->arg3);
-done:
        threadobj_lock(&task->thobj);
        threadobj_set_magic(&task->thobj, ~task_magic);
        threadobj_unlock(&task->thobj);
 
-       pthread_exit((void *)(long)ret);
+       return NULL;
 }
 
 /*
@@ -330,7 +329,8 @@ u_long t_create(const char *name, u_long prio,
        threadobj_init(&task->thobj, &idata);
 
        cta.prio = cprio;
-       cta.start = task_trampoline;
+       cta.prologue = task_prologue;
+       cta.run = task_trampoline;
        cta.arg = task;
        cta.stacksize = ustack;
        cta.detachstate = PTHREAD_CREATE_DETACHED;
diff --git a/lib/vxworks/taskLib.c b/lib/vxworks/taskLib.c
index b3755b6..c47919d 100644
--- a/lib/vxworks/taskLib.c
+++ b/lib/vxworks/taskLib.c
@@ -215,6 +215,13 @@ static struct registry_operations registry_ops;
 
 #endif /* CONFIG_XENO_REGISTRY */
 
+static int task_prologue(void *arg)
+{
+       struct wind_task *task = arg;
+
+       return __bt(threadobj_prologue(&task->thobj, task->name));
+}
+
 static void *task_trampoline(void *arg)
 {
        struct wind_task *task = arg;
@@ -223,12 +230,6 @@ static void *task_trampoline(void *arg)
        struct service svc;
        int ret;
 
-       ret = __bt(threadobj_prologue(&task->thobj, task->name));
-       if (ret) {
-               backtrace_check();
-               goto done;
-       }
-
        CANCEL_DEFER(svc);
 
        write_lock_nocancel(&wind_task_lock);
@@ -259,12 +260,12 @@ static void *task_trampoline(void *arg)
        args->entry(args->arg0, args->arg1, args->arg2, args->arg3,
                    args->arg4, args->arg5, args->arg6, args->arg7,
                    args->arg8, args->arg9);
-done:
+
        threadobj_lock(&task->thobj);
        threadobj_set_magic(&task->thobj, ~task_magic);
        threadobj_unlock(&task->thobj);
 
-       pthread_exit((void *)(long)ret);
+       return NULL;
 }
 
 /*
@@ -373,7 +374,8 @@ static STATUS __taskInit(struct wind_task *task,
        registry_init_file(&task->fsobj, &registry_ops, 0);
 
        cta.prio = cprio;
-       cta.start = task_trampoline;
+       cta.prologue = task_prologue;
+       cta.run = task_trampoline;
        cta.arg = task;
        cta.stacksize = stacksize;
        cta.detachstate = PTHREAD_CREATE_DETACHED;


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

Reply via email to