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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Sun Nov 13 18:12:11 2011 +0100

alchemy: close race upon registration of published objects

Object control blocks indexed within a cluster must be fully built
before they get published through *cluster_addobj(), at which point
they could be referred to immediately from another task as the
publishing task gets preempted.

However, care is taken not to trash the original object _descriptor_
(not control block) in case -EEXIST is raised, since we should still
be able to use the previously registered object in such a case.

---

 lib/alchemy/alarm.c  |   21 ++++++++++-----------
 lib/alchemy/buffer.c |   19 ++++++++++---------
 lib/alchemy/cond.c   |   22 +++++++++++-----------
 lib/alchemy/event.c  |   29 ++++++++++++++---------------
 lib/alchemy/heap.c   |   38 +++++++++++++++++++-------------------
 lib/alchemy/mutex.c  |   21 ++++++++++-----------
 lib/alchemy/pipe.c   |   37 ++++++++++++++++++-------------------
 lib/alchemy/queue.c  |   39 +++++++++++++++++++--------------------
 lib/alchemy/sem.c    |   27 ++++++++++++---------------
 lib/alchemy/task.c   |   26 ++++++++++++++++----------
 10 files changed, 139 insertions(+), 140 deletions(-)

diff --git a/lib/alchemy/alarm.c b/lib/alchemy/alarm.c
index aaf28bc..c86fc6d 100644
--- a/lib/alchemy/alarm.c
+++ b/lib/alchemy/alarm.c
@@ -96,29 +96,27 @@ int rt_alarm_create(RT_ALARM *alarm, const char *name,
                goto out;
        }
 
-       alchemy_build_name(acb->name, name, &alarm_namegen);
-
-       if (pvcluster_addobj(&alchemy_alarm_table, acb->name, &acb->cobj)) {
-               ret = -EEXIST;
-               goto fail_cluster;
-       }
-
        ret = timerobj_init(&acb->tmobj);
        if (ret)
-               goto fail_timer;
+               goto fail;
 
+       alchemy_build_name(acb->name, name, &alarm_namegen);
        acb->handler = handler;
        acb->arg = arg;
        acb->expiries = 0;
        acb->magic = alarm_magic;
        alarm->handle = (uintptr_t)acb;
 
+       if (pvcluster_addobj(&alchemy_alarm_table, acb->name, &acb->cobj)) {
+               timerobj_destroy(&acb->tmobj);
+               ret = -EEXIST;
+               goto fail;
+       }
+
        COPPERPLATE_UNPROTECT(svc);
 
        return 0;
-fail_timer:
-       pvcluster_delobj(&alchemy_alarm_table, &acb->cobj);
-fail_cluster:
+fail:
        pvfree(acb);
 out:
        COPPERPLATE_UNPROTECT(svc);
@@ -141,6 +139,7 @@ int rt_alarm_delete(RT_ALARM *alarm)
        timerobj_destroy(&acb->tmobj);
        pvcluster_delobj(&alchemy_alarm_table, &acb->cobj);
        acb->magic = ~alarm_magic;
+       pvfree(acb);
 out:
        COPPERPLATE_UNPROTECT(svc);
 
diff --git a/lib/alchemy/buffer.c b/lib/alchemy/buffer.c
index 3f7a6de..27642af 100644
--- a/lib/alchemy/buffer.c
+++ b/lib/alchemy/buffer.c
@@ -111,23 +111,23 @@ int rt_buffer_create(RT_BUFFER *bf, const char *name,
        }
 
        alchemy_build_name(bcb->name, name, &buffer_namegen);
-
-       if (syncluster_addobj(&alchemy_buffer_table, bcb->name, &bcb->cobj)) {
-               ret = -EEXIST;
-               goto fail_register;
-       }
-
-       if (mode & B_PRIO)
-               sobj_flags = SYNCOBJ_PRIO;
-
        bcb->magic = buffer_magic;
        bcb->mode = mode;
        bcb->bufsz = bufsz;
        bcb->rdoff = 0;
        bcb->wroff = 0;
        bcb->fillsz = 0;
+       if (mode & B_PRIO)
+               sobj_flags = SYNCOBJ_PRIO;
+
        syncobj_init(&bcb->sobj, sobj_flags,
                     fnref_put(libalchemy, buffer_finalize));
+
+       if (syncluster_addobj(&alchemy_buffer_table, bcb->name, &bcb->cobj)) {
+               ret = -EEXIST;
+               goto fail_register;
+       }
+
        bf->handle = mainheap_ref(bcb, uintptr_t);
 
        COPPERPLATE_UNPROTECT(svc);
@@ -135,6 +135,7 @@ int rt_buffer_create(RT_BUFFER *bf, const char *name,
        return 0;
 
 fail_register:
+       syncobj_uninit(&bcb->sobj);
        xnfree(bcb->buf);
 fail_bufalloc:
        xnfree(bcb);
diff --git a/lib/alchemy/cond.c b/lib/alchemy/cond.c
index dbc45cf..5d3a6ba 100644
--- a/lib/alchemy/cond.c
+++ b/lib/alchemy/cond.c
@@ -66,6 +66,7 @@ int rt_cond_create(RT_COND *cond, const char *name)
        struct alchemy_cond *ccb;
        pthread_condattr_t cattr;
        struct service svc;
+       int ret = 0;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -74,29 +75,28 @@ int rt_cond_create(RT_COND *cond, const char *name)
 
        ccb = xnmalloc(sizeof(*ccb));
        if (ccb == NULL) {
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        alchemy_build_name(ccb->name, name, &cond_namegen);
-
-       if (syncluster_addobj(&alchemy_cond_table, ccb->name, &ccb->cobj)) {
-               xnfree(ccb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
-       }
-
        __RT(pthread_condattr_init(&cattr));
        __RT(pthread_condattr_setpshared(&cattr, mutex_scope_attribute));
        __RT(pthread_condattr_setclock(&cattr, CLOCK_COPPERPLATE));
        __RT(pthread_cond_init(&ccb->cond, &cattr));
        __RT(pthread_condattr_destroy(&cattr));
        ccb->magic = cond_magic;
-       cond->handle = mainheap_ref(ccb, uintptr_t);
 
+       if (syncluster_addobj(&alchemy_cond_table, ccb->name, &ccb->cobj)) {
+               __RT(pthread_cond_destroy(&ccb->cond));
+               xnfree(ccb);
+               ret = -EEXIST;
+       } else
+               cond->handle = mainheap_ref(ccb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_cond_delete(RT_COND *cond)
diff --git a/lib/alchemy/event.c b/lib/alchemy/event.c
index 6392c90..fa8a98f 100644
--- a/lib/alchemy/event.c
+++ b/lib/alchemy/event.c
@@ -84,9 +84,9 @@ fnref_register(libalchemy, event_finalize);
 int rt_event_create(RT_EVENT *event, const char *name,
                    unsigned long ivalue, int mode)
 {
+       int sobj_flags = 0, ret = 0;
        struct alchemy_event *evcb;
        struct service svc;
-       int sobj_flags = 0;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -95,31 +95,30 @@ int rt_event_create(RT_EVENT *event, const char *name,
 
        evcb = xnmalloc(sizeof(*evcb));
        if (evcb == NULL) {
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        alchemy_build_name(evcb->name, name, &event_namegen);
-
-       if (syncluster_addobj(&alchemy_event_table, evcb->name, &evcb->cobj)) {
-               xnfree(evcb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
-       }
-
-       if (mode & EV_PRIO)
-               sobj_flags = SYNCOBJ_PRIO;
-
        evcb->magic = event_magic;
        evcb->value = ivalue;
        evcb->mode = mode;
+       if (mode & EV_PRIO)
+               sobj_flags = SYNCOBJ_PRIO;
+
        syncobj_init(&evcb->sobj, sobj_flags,
                     fnref_put(libalchemy, event_finalize));
-       event->handle = mainheap_ref(evcb, uintptr_t);
 
+       if (syncluster_addobj(&alchemy_event_table, evcb->name, &evcb->cobj)) {
+               syncobj_uninit(&evcb->sobj);
+               xnfree(evcb);
+               ret = -EEXIST;
+       } else
+               event->handle = mainheap_ref(evcb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_event_delete(RT_EVENT *event)
diff --git a/lib/alchemy/heap.c b/lib/alchemy/heap.c
index 03a7857..f09b028 100644
--- a/lib/alchemy/heap.c
+++ b/lib/alchemy/heap.c
@@ -86,8 +86,8 @@ int rt_heap_create(RT_HEAP *heap,
                   const char *name, size_t heapsize, int mode)
 {
        struct alchemy_heap *hcb;
+       int sobj_flags = 0, ret;
        struct service svc;
-       int sobj_flags = 0;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -97,44 +97,44 @@ int rt_heap_create(RT_HEAP *heap,
 
        COPPERPLATE_PROTECT(svc);
 
+       ret = -ENOMEM;
        hcb = xnmalloc(sizeof(*hcb));
        if (hcb == NULL)
-               goto no_mem;
-
-       alchemy_build_name(hcb->name, name, &heap_namegen);
-
-       if (syncluster_addobj(&alchemy_heap_table, hcb->name, &hcb->cobj)) {
-               xnfree(hcb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
-       }
+               goto out;
 
        /*
         * The memory pool has to be part of the main heap for proper
         * sharing between processes.
         */
        if (heapobj_init_shareable(&hcb->hobj, NULL, heapsize)) {
-               syncluster_delobj(&alchemy_heap_table, &hcb->cobj);
                xnfree(hcb);
-       no_mem:
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
+               goto out;
        }
 
-       if (mode & H_PRIO)
-               sobj_flags = SYNCOBJ_PRIO;
-
+       alchemy_build_name(hcb->name, name, &heap_namegen);
        hcb->magic = heap_magic;
        hcb->mode = mode;
        hcb->size = heapsize;
        hcb->sba = NULL;
+
+       if (mode & H_PRIO)
+               sobj_flags = SYNCOBJ_PRIO;
+
        syncobj_init(&hcb->sobj, sobj_flags,
                     fnref_put(libalchemy, heap_finalize));
-       heap->handle = mainheap_ref(hcb, uintptr_t);
 
+       ret = 0;
+       if (syncluster_addobj(&alchemy_heap_table, hcb->name, &hcb->cobj)) {
+               syncobj_uninit(&hcb->sobj);
+               heapobj_destroy(&hcb->hobj);
+               xnfree(hcb);
+               ret = -EEXIST;
+       } else
+               heap->handle = mainheap_ref(hcb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_heap_delete(RT_HEAP *heap)
diff --git a/lib/alchemy/mutex.c b/lib/alchemy/mutex.c
index 2647dab..91a54d7 100644
--- a/lib/alchemy/mutex.c
+++ b/lib/alchemy/mutex.c
@@ -66,6 +66,7 @@ int rt_mutex_create(RT_MUTEX *mutex, const char *name)
        struct alchemy_mutex *mcb;
        pthread_mutexattr_t mattr;
        struct service svc;
+       int ret = 0;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -74,19 +75,12 @@ int rt_mutex_create(RT_MUTEX *mutex, const char *name)
 
        mcb = xnmalloc(sizeof(*mcb));
        if (mcb == NULL) {
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }
 
        alchemy_build_name(mcb->name, name, &mutex_namegen);
        mcb->owner = no_alchemy_task;
-
-       if (syncluster_addobj(&alchemy_mutex_table, mcb->name, &mcb->cobj)) {
-               xnfree(mcb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
-       }
-
        __RT(pthread_mutexattr_init(&mattr));
        __RT(pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT));
        __RT(pthread_mutexattr_setpshared(&mattr, mutex_scope_attribute));
@@ -97,11 +91,16 @@ int rt_mutex_create(RT_MUTEX *mutex, const char *name)
        __RT(pthread_mutex_init(&mcb->lock, &mattr));
        __RT(pthread_mutexattr_destroy(&mattr));
        mcb->magic = mutex_magic;
-       mutex->handle = mainheap_ref(mcb, uintptr_t);
 
+       if (syncluster_addobj(&alchemy_mutex_table, mcb->name, &mcb->cobj)) {
+               xnfree(mcb);
+               ret = -EEXIST;
+       } else
+               mutex->handle = mainheap_ref(mcb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_mutex_delete(RT_MUTEX *mutex)
diff --git a/lib/alchemy/pipe.c b/lib/alchemy/pipe.c
index e6d4044..2bd2de5 100644
--- a/lib/alchemy/pipe.c
+++ b/lib/alchemy/pipe.c
@@ -70,7 +70,7 @@ int rt_pipe_create(RT_PIPE *pipe,
        struct alchemy_pipe *pcb;
        struct service svc;
        size_t streambufsz;
-       int ret = 0, sock;
+       int ret, sock;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -79,16 +79,8 @@ int rt_pipe_create(RT_PIPE *pipe,
 
        pcb = xnmalloc(sizeof(*pcb));
        if (pcb == NULL) {
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
-       }
-
-       alchemy_build_name(pcb->name, name, &pipe_namegen);
-
-       if (syncluster_addobj(&alchemy_pipe_table, pcb->name, &pcb->cobj)) {
-               xnfree(pcb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
+               ret = -ENOMEM;
+               goto out;
        }
 
        sock = __RT(socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP));
@@ -105,42 +97,49 @@ int rt_pipe_create(RT_PIPE *pipe,
                ret = __RT(setsockopt(sock, SOL_XDDP, XDDP_LABEL,
                                      &plabel, sizeof(plabel)));
                if (ret)
-                       goto fail;
+                       goto fail_sockopt;
        }
 
        if (poolsize > 0) {
                ret = setsockopt(pcb->sock, SOL_XDDP, XDDP_POOLSZ,
                                 &poolsize, sizeof(poolsize));
                if (ret)
-                       goto fail;
+                       goto fail_sockopt;
        }
 
        streambufsz = ALCHEMY_PIPE_STREAMSZ;
        ret = __RT(setsockopt(pcb->sock, SOL_XDDP, XDDP_BUFSZ,
                              &streambufsz, streambufsz));
        if (ret)
-               goto fail;
+               goto fail_sockopt;
 
        memset(&saddr, 0, sizeof(saddr));
        saddr.sipc_family = AF_RTIPC;
        saddr.sipc_port = minor;
        ret = bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
        if (ret)
-               goto fail;
+               goto fail_sockopt;
 
+       alchemy_build_name(pcb->name, name, &pipe_namegen);
        pcb->sock = sock;
        pcb->magic = pipe_magic;
+
+       if (syncluster_addobj(&alchemy_pipe_table, pcb->name, &pcb->cobj)) {
+               ret = -EEXIST;
+               goto fail_register;
+       }
+
        pipe->handle = mainheap_ref(pcb, uintptr_t);
-out:
+
        COPPERPLATE_UNPROTECT(svc);
 
        return 0;
-fail:
+fail_sockopt:
        ret = -errno;
+fail_register:
        __RT(close(sock));
-       syncluster_delobj(&alchemy_pipe_table, &pcb->cobj);
        xnfree(pcb);
-
+out:
        COPPERPLATE_UNPROTECT(svc);
 
        return ret;     
diff --git a/lib/alchemy/queue.c b/lib/alchemy/queue.c
index d87b597..9e6cdd0 100644
--- a/lib/alchemy/queue.c
+++ b/lib/alchemy/queue.c
@@ -87,8 +87,8 @@ int rt_queue_create(RT_QUEUE *queue, const char *name,
                    size_t poolsize, size_t qlimit, int mode)
 {
        struct alchemy_queue *qcb;
+       int sobj_flags = 0, ret;
        struct service svc;
-       int sobj_flags = 0;
 
        if (threadobj_irq_p())
                return -EPERM;
@@ -98,45 +98,44 @@ int rt_queue_create(RT_QUEUE *queue, const char *name,
 
        COPPERPLATE_PROTECT(svc);
 
+       ret = -ENOMEM;
        qcb = xnmalloc(sizeof(*qcb));
        if (qcb == NULL)
-               goto no_mem;
-
-       alchemy_build_name(qcb->name, name, &queue_namegen);
-
-       if (syncluster_addobj(&alchemy_queue_table, qcb->name, &qcb->cobj)) {
-               xnfree(qcb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
-       }
-
+               goto out;
        /*
         * The message pool has to be part of the main heap for proper
         * sharing between processes.
         */
        if (heapobj_init_shareable(&qcb->hobj, NULL, poolsize)) {
-               syncluster_delobj(&alchemy_queue_table, &qcb->cobj);
                xnfree(qcb);
-       no_mem:
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
+               goto out;
        }
 
-       if (mode & Q_PRIO)
-               sobj_flags = SYNCOBJ_PRIO;
-
+       alchemy_build_name(qcb->name, name, &queue_namegen);
        qcb->magic = queue_magic;
        qcb->mode = mode;
        qcb->limit = qlimit;
        list_init(&qcb->mq);
        qcb->mcount = 0;
+
+       if (mode & Q_PRIO)
+               sobj_flags = SYNCOBJ_PRIO;
+
        syncobj_init(&qcb->sobj, sobj_flags,
                     fnref_put(libalchemy, queue_finalize));
-       queue->handle = mainheap_ref(qcb, uintptr_t);
 
+       ret = 0;
+       if (syncluster_addobj(&alchemy_queue_table, qcb->name, &qcb->cobj)) {
+               heapobj_destroy(&qcb->hobj);
+               syncobj_uninit(&qcb->sobj);
+               xnfree(qcb);
+               ret = -EEXIST;
+       } else
+               queue->handle = mainheap_ref(qcb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_queue_delete(RT_QUEUE *queue)
diff --git a/lib/alchemy/sem.c b/lib/alchemy/sem.c
index c618d4e..d170ab5 100644
--- a/lib/alchemy/sem.c
+++ b/lib/alchemy/sem.c
@@ -88,16 +88,8 @@ int rt_sem_create(RT_SEM *sem, const char *name,
 
        scb = xnmalloc(sizeof(*scb));
        if (scb == NULL) {
-               COPPERPLATE_UNPROTECT(svc);
-               return -ENOMEM;
-       }
-
-       alchemy_build_name(scb->name, name, &sem_namegen);
-
-       if (syncluster_addobj(&alchemy_sem_table, scb->name, &scb->cobj)) {
-               xnfree(scb);
-               COPPERPLATE_UNPROTECT(svc);
-               return -EEXIST;
+               ret = -ENOMEM;
+               goto out;
        }
 
        if (mode & S_PRIO)
@@ -106,18 +98,23 @@ int rt_sem_create(RT_SEM *sem, const char *name,
        ret = semobj_init(&scb->smobj, smobj_flags, icount,
                          fnref_put(libalchemy, sem_finalize));
        if (ret) {
-               syncluster_delobj(&alchemy_sem_table, &scb->cobj);
                xnfree(scb);
-               COPPERPLATE_UNPROTECT(svc);
-               return ret;
+               goto out;
        }
 
+       alchemy_build_name(scb->name, name, &sem_namegen);
        scb->magic = sem_magic;
-       sem->handle = mainheap_ref(scb, uintptr_t);
 
+       if (syncluster_addobj(&alchemy_sem_table, scb->name, &scb->cobj)) {
+               semobj_destroy(&scb->smobj);
+               xnfree(scb);
+               ret = -EEXIST;
+       } else
+               sem->handle = mainheap_ref(scb, uintptr_t);
+out:
        COPPERPLATE_UNPROTECT(svc);
 
-       return 0;
+       return ret;
 }
 
 int rt_sem_delete(RT_SEM *sem)
diff --git a/lib/alchemy/task.c b/lib/alchemy/task.c
index 1454b3d..8891e41 100644
--- a/lib/alchemy/task.c
+++ b/lib/alchemy/task.c
@@ -213,7 +213,7 @@ out:
        pthread_exit((void *)(long)ret);
 }
 
-static int create_tcb(struct alchemy_task **tcbp,
+static int create_tcb(struct alchemy_task **tcbp, RT_TASK *task,
                      const char *name, int prio, int mode)
 {
        struct threadobj_init_data idata;
@@ -256,12 +256,24 @@ static int create_tcb(struct alchemy_task **tcbp,
        idata.priority = prio;
        threadobj_init(&tcb->thobj, &idata);
 
+       *tcbp = tcb;
+
+       /*
+        * CAUTION: The task control block must be fully built before
+        * we publish it through syncluster_addobj(), at which point
+        * it could be referred to immediately from another task as we
+        * got preempted. In addition, the task descriptor must be
+        * updated prior to starting the task.
+        */
+       tcb->self.handle = mainheap_ref(tcb, uintptr_t);
+
        if (syncluster_addobj(&alchemy_task_table, tcb->name, &tcb->cobj)) {
                delete_tcb(tcb);
                return -EEXIST;
        }
 
-       *tcbp = tcb;
+       if (task)
+               task->handle = tcb->self.handle;
 
        return 0;
 }
@@ -283,12 +295,11 @@ int rt_task_create(RT_TASK *task, const char *name,
 
        COPPERPLATE_PROTECT(svc);
 
-       ret = create_tcb(&tcb, name, prio, mode);
+       ret = create_tcb(&tcb, task, name, prio, mode);
        if (ret)
                goto out;
 
        /* We want this to be set prior to spawning the thread. */
-       task->handle = mainheap_ref(tcb, uintptr_t);
        tcb->self = *task;
 
        ret = __bt(copperplate_create_thread(prio, task_trampoline, tcb,
@@ -388,15 +399,10 @@ int rt_task_shadow(RT_TASK *task, const char *name, int 
prio, int mode)
 
        COPPERPLATE_PROTECT(svc);
 
-       ret = create_tcb(&tcb, name, prio, mode);
+       ret = create_tcb(&tcb, task, name, prio, mode);
        if (ret)
                goto out;
 
-       tcb->self.handle = mainheap_ref(tcb, uintptr_t);
-
-       if (task)
-               *task = tcb->self;
-
        threadobj_start(&tcb->thobj); /* We won't wait in prologue. */
        ret = task_prologue(tcb);
        if (ret) {


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

Reply via email to