Module: xenomai-forge Branch: master Commit: 5ca3688ec48be374d72212df9b61701ba2ee54ae URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=5ca3688ec48be374d72212df9b61701ba2ee54ae
Author: Philippe Gerum <r...@xenomai.org> Date: Mon Nov 7 16:47:14 2011 +0100 copperplate/threadobj, lib: introduce pre-allocated wait_struct Each service using a wait_struct for passing and retrieving wait data across syncobj_pend() calls had to allocate a wait_struct dynamically for each wait operation. In pshared mode, this amounts to xnmalloc() and xnfree() calls each time, which is sub-optimal. Because a thread cannot wait for more than a single "event", only a single wait struct is needed for it at any point in time. Additionally, we do know the type of each wait struct that might be involved in a thread's lifetime at build time. Therefore, we may pre-allocate a general wait union large enough to map all known wait_struct types, living right after the thread control block in memory. To this end, this patch introduces a new service threadobj_allocate(T, mptr, W), to allocate a control block for a new thread/task of type T, followed by enough space to map a wait union of type W (mptr shall be the name of the base threadobj member within T). A pointer to this memory will be returned by threadobj_prepare_wait(), which replaces the former threadobj_alloc_wait() service. In turn, threadobj_free_wait() does not take any argument as it works implicitly on the pre-allocated per-thread wait union memory. --- include/copperplate/cluster.h | 4 ++ include/copperplate/threadobj.h | 81 ++++++++++++-------------------------- lib/alchemy/buffer.c | 16 ++------ lib/alchemy/event.c | 10 +--- lib/alchemy/heap.c | 10 +--- lib/alchemy/queue.c | 11 +---- lib/alchemy/task.c | 27 ++++++++----- lib/copperplate/cluster.c | 20 +++------- lib/copperplate/threadobj.c | 29 +++++++++++++- lib/psos/task.c | 12 ++++-- lib/vxworks/taskLib.c | 8 +++- 11 files changed, 108 insertions(+), 120 deletions(-) diff --git a/include/copperplate/cluster.h b/include/copperplate/cluster.h index ac8081e..377f351 100644 --- a/include/copperplate/cluster.h +++ b/include/copperplate/cluster.h @@ -78,6 +78,10 @@ struct syncluster { #endif /* !CONFIG_XENO_PSHARED */ +struct syncluster_wait_struct { + const char *name; +}; + #ifdef __cplusplus extern "C" { #endif diff --git a/include/copperplate/threadobj.h b/include/copperplate/threadobj.h index d6be354..220467e 100644 --- a/include/copperplate/threadobj.h +++ b/include/copperplate/threadobj.h @@ -134,9 +134,10 @@ struct threadobj { void *ptr; size_t size; } buffer; - } wait_u; /* XXX: deprecated by wait_struct */ + } wait_u; /* XXX: deprecated by wait_union */ void (*wait_hook)(struct threadobj *thobj, int status); - void *wait_struct; + void *wait_union; + size_t wait_size; struct threadobj_corespec core; pthread_cond_t barrier; @@ -164,6 +165,15 @@ extern int threadobj_irq_prio; extern "C" { #endif +void *__threadobj_alloc(size_t tcb_struct_size, + size_t wait_union_size, + int thobj_offset); + +static inline void threadobj_free(void *p) +{ + xnfree(p); +} + void threadobj_init(struct threadobj *thobj, struct threadobj_init_data *idata); @@ -218,6 +228,13 @@ void threadobj_pkg_init(void); } #endif +#define threadobj_alloc(T, __mptr, W) \ + ({ \ + void *__p; \ + __p = __threadobj_alloc(sizeof(T), sizeof(W), offsetof(T, __mptr)); \ + __p; \ + }) + static inline int threadobj_get_priority(struct threadobj *thobj) { return thobj->priority; @@ -303,74 +320,28 @@ static inline int threadobj_get_errno(struct threadobj *thobj) return *thobj->errno_pointer; } -#ifdef CONFIG_XENO_PSHARED - static inline int threadobj_local_p(struct threadobj *thobj) { +#ifdef CONFIG_XENO_PSHARED return thobj->cnode == __this_node.id; -} - -/* - * In shared processing mode, wait structs may be accessed by remote - * processes from the same session, so we allocate them from the - * shared heap. - */ -#define threadobj_alloc_wait(T) \ - ({ \ - struct threadobj *__thobj = threadobj_current(); \ - typeof(T) *__p; \ - assert(__thobj != NULL); \ - assert(__thobj->wait_struct == NULL); \ - __p = xnmalloc(sizeof(T)); \ - __thobj->wait_struct = __p; \ - __p; \ - }) - -#define threadobj_free_wait(__p) \ - ({ \ - struct threadobj *__thobj = threadobj_current(); \ - assert(__thobj != NULL); \ - assert(__thobj->wait_struct == __p); \ - __thobj->wait_struct = NULL; \ - xnfree(__p); \ - }) - #else - -#include <alloca.h> - -static inline int threadobj_local_p(struct threadobj *thobj) -{ return 1; +#endif } -/* - * In purely local mode, we can allocate wait structs from the stack. - */ -#define threadobj_alloc_wait(T) \ - ({ \ - struct threadobj *__thobj = threadobj_current(); \ - typeof(T) *__p; \ - assert(__thobj != NULL); \ - assert(__thobj->wait_struct == NULL); \ - __p = alloca(sizeof(T)); \ - __thobj->wait_struct = __p; \ - __p; \ - }) - -#define threadobj_free_wait(__p) \ +#define threadobj_prepare_wait(T) \ ({ \ struct threadobj *__thobj = threadobj_current(); \ assert(__thobj != NULL); \ - assert(__thobj->wait_struct == __p); \ - __thobj->wait_struct = NULL; \ + assert(sizeof(typeof(T)) <= __thobj->wait_size); \ + __thobj->wait_union; \ }) -#endif +#define threadobj_finish_wait() do { } while (0) static inline void *threadobj_get_wait(struct threadobj *thobj) { - return thobj->wait_struct; + return thobj->wait_union; } static inline const char *threadobj_get_name(struct threadobj *thobj) diff --git a/lib/alchemy/buffer.c b/lib/alchemy/buffer.c index 5ce2686..3f7a6de 100644 --- a/lib/alchemy/buffer.c +++ b/lib/alchemy/buffer.c @@ -270,11 +270,7 @@ redo: if (wait == NULL) { timespec = alchemy_get_timespec(timeout, &ts); - wait = threadobj_alloc_wait(struct alchemy_buffer_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } + wait = threadobj_prepare_wait(struct alchemy_buffer_wait); } wait->size = len; @@ -289,7 +285,7 @@ done: put_alchemy_buffer(bcb, &syns); out: if (wait) - threadobj_free_wait(wait); + threadobj_finish_wait(); COPPERPLATE_UNPROTECT(svc); @@ -404,11 +400,7 @@ redo: if (wait == NULL) { timespec = alchemy_get_timespec(timeout, &ts); - wait = threadobj_alloc_wait(struct alchemy_buffer_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } + wait = threadobj_prepare_wait(struct alchemy_buffer_wait); } wait->size = len; @@ -423,7 +415,7 @@ done: put_alchemy_buffer(bcb, &syns); out: if (wait) - threadobj_free_wait(wait); + threadobj_finish_wait(); COPPERPLATE_UNPROTECT(svc); diff --git a/lib/alchemy/event.c b/lib/alchemy/event.c index 1af6806..6392c90 100644 --- a/lib/alchemy/event.c +++ b/lib/alchemy/event.c @@ -187,11 +187,7 @@ int rt_event_wait_until(RT_EVENT *event, goto done; } - wait = threadobj_alloc_wait(struct alchemy_event_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } + wait = threadobj_prepare_wait(struct alchemy_event_wait); wait->mask = mask; wait->mode = mode; @@ -200,13 +196,13 @@ int rt_event_wait_until(RT_EVENT *event, ret = syncobj_pend(&evcb->sobj, timespec, &syns); if (ret) { if (ret == -EIDRM) { - threadobj_free_wait(wait); + threadobj_finish_wait(); goto out; } } else *mask_r = wait->mask; - threadobj_free_wait(wait); + threadobj_finish_wait(); done: put_alchemy_event(evcb, &syns); out: diff --git a/lib/alchemy/heap.c b/lib/alchemy/heap.c index d7a622e..03a7857 100644 --- a/lib/alchemy/heap.c +++ b/lib/alchemy/heap.c @@ -215,23 +215,19 @@ int rt_heap_alloc(RT_HEAP *heap, timespec = alchemy_get_timespec(timeout, &ts); - wait = threadobj_alloc_wait(struct alchemy_heap_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } + wait = threadobj_prepare_wait(struct alchemy_heap_wait); wait->size = size; ret = syncobj_pend(&hcb->sobj, timespec, &syns); if (ret) { if (ret == -EIDRM) { - threadobj_free_wait(wait); + threadobj_finish_wait(); goto out; } } else p = wait->ptr; - threadobj_free_wait(wait); + threadobj_finish_wait(); done: *blockp = p; diff --git a/lib/alchemy/queue.c b/lib/alchemy/queue.c index 0a6e98c..d87b597 100644 --- a/lib/alchemy/queue.c +++ b/lib/alchemy/queue.c @@ -368,18 +368,13 @@ ssize_t rt_queue_receive_until(RT_QUEUE *queue, goto done; } - wait = threadobj_alloc_wait(struct alchemy_queue_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } - + wait = threadobj_prepare_wait(struct alchemy_queue_wait); timespec = alchemy_get_timespec(timeout, &ts); ret = syncobj_pend(&qcb->sobj, timespec, &syns); if (ret) { if (ret == -EIDRM) { - threadobj_free_wait(wait); + threadobj_finish_wait(); goto out; } } else { @@ -388,7 +383,7 @@ ssize_t rt_queue_receive_until(RT_QUEUE *queue, ret = (ssize_t)msg->size; } - threadobj_free_wait(wait); + threadobj_finish_wait(); done: put_alchemy_queue(qcb, &syns); out: diff --git a/lib/alchemy/task.c b/lib/alchemy/task.c index 3ff9d95..3b9ab10 100644 --- a/lib/alchemy/task.c +++ b/lib/alchemy/task.c @@ -26,8 +26,18 @@ #include <copperplate/heapobj.h> #include "internal.h" #include "task.h" +#include "buffer.h" +#include "event.h" +#include "queue.h" #include "timer.h" +union alchemy_wait_union { + struct alchemy_task_wait task_wait; + struct alchemy_buffer_wait buffer_wait; + struct alchemy_event_wait event_wait; + struct alchemy_queue_wait queue_wait; +}; + struct syncluster alchemy_task_table; static struct alchemy_namegen task_namegen = { @@ -147,7 +157,7 @@ static void task_finalizer(struct threadobj *thobj) syncobj_destroy(&tcb->sobj_msg, &syns); threadobj_destroy(&tcb->thobj); - xnfree(tcb); + threadobj_free(tcb); } static int task_prologue(struct alchemy_task *tcb) @@ -217,7 +227,8 @@ static int create_tcb(struct alchemy_task **tcbp, if (mode & ~(T_CPUMASK|T_LOCK)) return -EINVAL; - tcb = xnmalloc(sizeof(*tcb)); + tcb = threadobj_alloc(struct alchemy_task, thobj, + union alchemy_wait_union); if (tcb == NULL) return -ENOMEM; @@ -260,7 +271,7 @@ static void delete_tcb(struct alchemy_task *tcb) threadobj_destroy(&tcb->thobj); syncobj_uninit(&tcb->sobj_safe); syncobj_uninit(&tcb->sobj_msg); - xnfree(tcb); + threadobj_free(tcb); } int rt_task_create(RT_TASK *task, const char *name, @@ -751,11 +762,7 @@ ssize_t rt_task_send_until(RT_TASK *task, } /* Get space for the reply. */ - wait = threadobj_alloc_wait(struct alchemy_task_wait); - if (wait == NULL) { - ret = -ENOMEM; - goto done; - } + wait = threadobj_prepare_wait(struct alchemy_task_wait); /* * Compute the next flow identifier, making sure that we won't @@ -775,13 +782,13 @@ ssize_t rt_task_send_until(RT_TASK *task, ret = syncobj_pend(&tcb->sobj_msg, timespec, &syns); if (ret) { - threadobj_free_wait(wait); + threadobj_finish_wait(); if (ret == -EIDRM) goto out; goto done; } - threadobj_free_wait(wait); + threadobj_finish_wait(); done: syncobj_unlock(&tcb->sobj_msg, &syns); out: diff --git a/lib/copperplate/cluster.c b/lib/copperplate/cluster.c index c084161..ee29206 100644 --- a/lib/copperplate/cluster.c +++ b/lib/copperplate/cluster.c @@ -97,10 +97,6 @@ #include "copperplate/threadobj.h" #include "copperplate/debug.h" -struct syncluster_wait_struct { - const char *name; -}; - #ifdef CONFIG_XENO_PSHARED int cluster_init(struct cluster *c, const char *name) @@ -297,10 +293,8 @@ int syncluster_findobj(struct syncluster *sc, break; } if (wait == NULL) { - wait = threadobj_alloc_wait(struct syncluster_wait_struct); - if (wait == NULL) { - return __bt(-ENOMEM); - } + wait = threadobj_prepare_wait(struct syncluster_wait_struct); + wait->name = name; } ret = syncobj_pend(sc->sobj, timeout, &syns); if (ret) { @@ -313,7 +307,7 @@ int syncluster_findobj(struct syncluster *sc, syncobj_unlock(sc->sobj, &syns); out: if (wait) - threadobj_free_wait(wait); + threadobj_finish_wait(); return ret; } @@ -447,10 +441,8 @@ int pvsyncluster_findobj(struct pvsyncluster *sc, break; } if (wait == NULL) { - wait = threadobj_alloc_wait(struct syncluster_wait_struct); - if (wait == NULL) { - return __bt(-ENOMEM); - } + wait = threadobj_prepare_wait(struct syncluster_wait_struct); + wait->name = name; } ret = syncobj_pend(&sc->sobj, timeout, &syns); if (ret) { @@ -463,7 +455,7 @@ int pvsyncluster_findobj(struct pvsyncluster *sc, syncobj_unlock(&sc->sobj, &syns); out: if (wait) - threadobj_free_wait(wait); + threadobj_finish_wait(); return ret; } diff --git a/lib/copperplate/threadobj.c b/lib/copperplate/threadobj.c index 83ff673..f8c0885 100644 --- a/lib/copperplate/threadobj.c +++ b/lib/copperplate/threadobj.c @@ -35,9 +35,14 @@ #include "copperplate/traceobj.h" #include "copperplate/threadobj.h" #include "copperplate/syncobj.h" +#include "copperplate/cluster.h" #include "copperplate/clockobj.h" #include "copperplate/debug.h" +union copperplate_wait_union { + struct syncluster_wait_struct syncluster_wait; +}; + /* * NOTE on cancellation handling: Most traditional RTOSes guarantee * that the task/thread delete operation is strictly synchronous, @@ -789,6 +794,28 @@ int threadobj_stat(struct threadobj *thobj, #endif /* CONFIG_XENO_MERCURY */ +void *__threadobj_alloc(size_t tcb_struct_size, + size_t wait_union_size, + int thobj_offset) +{ + struct threadobj *thobj; + void *p; + + if (wait_union_size < sizeof(union copperplate_wait_union)) + wait_union_size = sizeof(union copperplate_wait_union); + + tcb_struct_size = (tcb_struct_size+sizeof(double)-1) & ~(sizeof(double)-1); + p = xnmalloc(tcb_struct_size + wait_union_size); + if (p == NULL) + return NULL; + + thobj = p + thobj_offset; + thobj->wait_union = p + tcb_struct_size; + thobj->wait_size = wait_union_size; + + return p; +} + void threadobj_init(struct threadobj *thobj, struct threadobj_init_data *idata) { @@ -799,7 +826,7 @@ void threadobj_init(struct threadobj *thobj, thobj->tid = 0; thobj->tracer = NULL; thobj->wait_sobj = NULL; - thobj->wait_struct = NULL; + thobj->wait_union = NULL; thobj->finalizer = idata->finalizer; thobj->wait_hook = idata->wait_hook; thobj->schedlock_depth = 0; diff --git a/lib/psos/task.c b/lib/psos/task.c index 3560cbc..3fa8629 100644 --- a/lib/psos/task.c +++ b/lib/psos/task.c @@ -37,6 +37,9 @@ #include "task.h" #include "tm.h" +union psos_wait_union { +}; + struct cluster psos_task_table; static unsigned long anon_tids; @@ -163,7 +166,7 @@ static void task_finalizer(struct threadobj *thobj) syncobj_destroy(&task->sobj, &syns); threadobj_destroy(&task->thobj); - xnfree(task); + threadobj_free(task); } static void *task_trampoline(void *arg) @@ -258,7 +261,8 @@ u_long t_create(const char *name, u_long prio, COPPERPLATE_PROTECT(svc); - task = xnmalloc(sizeof(struct psos_task)); + task = threadobj_alloc(struct psos_task, + thobj, union psos_wait_union); if (task == NULL) { ret = ERR_NOTCB; goto out; @@ -272,7 +276,7 @@ u_long t_create(const char *name, u_long prio, * value based on the implementation default for such minimum. */ if (ustack > 0 && ustack < 8192) { - xnfree(task); + threadobj_free(task); ret = ERR_TINYSTK; goto out; } @@ -333,7 +337,7 @@ u_long t_create(const char *name, u_long prio, fail: syncobj_lock(&task->sobj, &syns); syncobj_destroy(&task->sobj, &syns); - xnfree(task); + threadobj_free(task); } out: COPPERPLATE_UNPROTECT(svc); diff --git a/lib/vxworks/taskLib.c b/lib/vxworks/taskLib.c index 75c37d2..989a02d 100644 --- a/lib/vxworks/taskLib.c +++ b/lib/vxworks/taskLib.c @@ -36,6 +36,9 @@ #include <copperplate/cluster.h> #include <vxworks/errnoLib.h> +union wind_wait_union { +}; + struct cluster wind_task_table; static unsigned long anon_tids; @@ -132,7 +135,7 @@ static void task_finalizer(struct threadobj *thobj) __RT(pthread_mutex_destroy(&task->safelock)); threadobj_destroy(&task->thobj); - xnfree(task); + threadobj_free(task); } /* @@ -400,7 +403,8 @@ static STATUS __taskInit(struct wind_task *task, static inline struct wind_task *alloc_task(void) { - return xnmalloc(sizeof(struct wind_task)); + return threadobj_alloc(struct wind_task, + thobj, union wind_wait_union); } STATUS taskInit(WIND_TCB *pTcb, _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git