Module: xenomai-forge Branch: next Commit: a48b8f640cad510a1101e380cc54ef2bf29afcd6 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=a48b8f640cad510a1101e380cc54ef2bf29afcd6
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, ¶m_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, ¶m_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, ¶m); 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, ¶m))); } +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, ®istry_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