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