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

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() becomes threadobj_finish_wait(), and
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     |   32 +++++++++++++++-
 lib/psos/task.c                 |   12 ++++--
 lib/vxworks/taskLib.c           |    8 +++-
 11 files changed, 111 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..685e979 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,6 @@ void threadobj_init(struct threadobj *thobj,
        thobj->tid = 0;
        thobj->tracer = NULL;
        thobj->wait_sobj = NULL;
-       thobj->wait_struct = NULL;
        thobj->finalizer = idata->finalizer;
        thobj->wait_hook = idata->wait_hook;
        thobj->schedlock_depth = 0;
@@ -808,6 +834,10 @@ void threadobj_init(struct threadobj *thobj,
        holder_init(&thobj->wait_link);
        thobj->suspend_hook = idata->suspend_hook;
        thobj->cnode = __this_node.id;
+       /*
+        * CAUTION: wait_union and wait_size have been set in
+        * __threadobj_alloc().
+        */
 
        __RT(pthread_condattr_init(&cattr));
        __RT(pthread_condattr_setpshared(&cattr, mutex_scope_attribute));
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

Reply via email to