Module: xenomai-forge Branch: master Commit: 07aab6ec30964b23a6a86b6be36360cabe8ec3de URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=07aab6ec30964b23a6a86b6be36360cabe8ec3de
Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> Date: Sun Dec 15 17:09:32 2013 +0100 cobalt/sem: export through registry --- include/cobalt/uapi/sem.h | 4 +- kernel/cobalt/posix/Makefile | 1 + kernel/cobalt/posix/init.c | 7 + kernel/cobalt/posix/nsem.c | 313 +++++++++++++++++++++++ kernel/cobalt/posix/sem.c | 574 +++++++++--------------------------------- kernel/cobalt/posix/sem.h | 33 ++- lib/cobalt/semaphore.c | 19 +- 7 files changed, 482 insertions(+), 469 deletions(-) diff --git a/include/cobalt/uapi/sem.h b/include/cobalt/uapi/sem.h index a1a9526..e011141 100644 --- a/include/cobalt/uapi/sem.h +++ b/include/cobalt/uapi/sem.h @@ -18,6 +18,8 @@ #ifndef _COBALT_UAPI_SEM_H #define _COBALT_UAPI_SEM_H +#include <cobalt/uapi/kernel/types.h> + #define COBALT_SEM_MAGIC (0x86860707) #define COBALT_NAMED_SEM_MAGIC (0x86860D0D) @@ -32,8 +34,8 @@ union cobalt_sem_union { sem_t native_sem; struct __shadow_sem { unsigned int magic; - struct cobalt_sem *sem; int datp_offset; + xnhandle_t handle; } shadow_sem; }; diff --git a/kernel/cobalt/posix/Makefile b/kernel/cobalt/posix/Makefile index d08442d..aad94a6 100644 --- a/kernel/cobalt/posix/Makefile +++ b/kernel/cobalt/posix/Makefile @@ -12,6 +12,7 @@ posix-y := \ mutex_attr.o \ registry.o \ sem.o \ + nsem.o \ select.o \ signal.o \ syscall.o \ diff --git a/kernel/cobalt/posix/init.c b/kernel/cobalt/posix/init.c index 4676d27..02e0b08 100644 --- a/kernel/cobalt/posix/init.c +++ b/kernel/cobalt/posix/init.c @@ -64,6 +64,7 @@ MODULE_LICENSE("GPL"); void cobalt_cleanup(void) { cobalt_syscall_cleanup(); + cobalt_nsem_pkg_cleanup(); cobalt_timer_pkg_cleanup(); cobalt_monitor_pkg_cleanup(); cobalt_event_pkg_cleanup(); @@ -83,6 +84,12 @@ int __init cobalt_init(void) if (ret) return ret; + ret = cobalt_nsem_pkg_init(); + if (ret) { + cobalt_syscall_cleanup(); + return ret; + } + cobalt_reg_pkg_init(64, 128); /* FIXME: replace with compilation constants. */ cobalt_mutex_pkg_init(); cobalt_sem_pkg_init(); diff --git a/kernel/cobalt/posix/nsem.c b/kernel/cobalt/posix/nsem.c new file mode 100644 index 0000000..c19faaf --- /dev/null +++ b/kernel/cobalt/posix/nsem.c @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2013 Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/list.h> +#include <linux/err.h> +#include <cobalt/kernel/lock.h> +#include <cobalt/kernel/heap.h> +#include "internal.h" +#include "sem.h" + +static struct hlist_head *nsem_hash; +DEFINE_XNLOCK(nsem_lock); +static unsigned mm_mult, mm_shift, nsem_hash_size; + +struct nsem { + struct cobalt_sem *sem; + struct mm_struct *mm; + struct __shadow_sem __user *usem; + unsigned refs; + struct hlist_node hlink; /* Link in global hash */ + struct list_head link; /* Link in per-process queue */ +}; + +static unsigned __attribute__((pure)) +nsem_hash_crunch(xnhandle_t handle, struct mm_struct *mm) +{ + unsigned long hash = (unsigned long)mm; + hash = handle + (((unsigned long long)hash * mm_mult) >> mm_shift); + return hash % nsem_hash_size; +} + +static struct nsem * +nsem_hash_search(xnhandle_t handle, struct mm_struct *mm) +{ + unsigned bucket = nsem_hash_crunch(handle, mm); + struct nsem *u; + + hlist_for_each_entry(u, &nsem_hash[bucket], hlink) + if (u->sem->handle == handle && u->mm == mm) + return u; + + return NULL; +} + +static void nsem_hash_enter(xnhandle_t handle, struct nsem *nsem) +{ + unsigned bucket = nsem_hash_crunch(handle, current->mm); + + hlist_add_head(&nsem->hlink, &nsem_hash[bucket]); +} + +static void nsem_hash_remove(struct nsem *u) +{ + hlist_del(&u->hlink); +} + +static struct __shadow_sem __user * +nsem_open(struct __shadow_sem __user *ushadow, const char *name, + int oflags, mode_t mode, unsigned value) +{ + struct __shadow_sem shadow; + struct cobalt_sem *sem; + struct nsem *u, *v; + xnhandle_t handle; + spl_t s; + int rc; + + if (name[0] != '/' || name[1] == '\0') + return ERR_PTR(-EINVAL); + + retry_bind: + rc = xnregistry_bind(&name[1], XN_NONBLOCK, XN_RELATIVE, &handle); + switch (rc) { + case 0: + /* Found */ + if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + return ERR_PTR(-EEXIST); + + xnlock_get_irqsave(&nsem_lock, s); + u = nsem_hash_search(handle, current->mm); + if (u) { + ++u->refs; + xnlock_put_irqrestore(&nsem_lock, s); + return u->usem; + } + xnlock_put_irqrestore(&nsem_lock, s); + + xnlock_get_irqsave(&nklock, s); + sem = xnregistry_fetch(handle); + if (sem && sem->magic != COBALT_SEM_MAGIC) { + xnlock_put_irqrestore(&nklock, s); + return ERR_PTR(-EINVAL); + } + + if (sem) { + ++sem->refs; + xnlock_put_irqrestore(&nklock, s); + } else { + xnlock_put_irqrestore(&nklock, s); + goto retry_bind; + } + break; + + case -EWOULDBLOCK: + /* Not found */ + if ((oflags & O_CREAT) == 0) + return ERR_PTR(-ENOENT); + + sem = cobalt_sem_init_inner + (&name[1], &shadow, SEM_PSHARED, value); + if (IS_ERR(sem)) { + rc = PTR_ERR(sem); + if (rc == -EEXIST) + goto retry_bind; + return ERR_PTR(rc); + } + + if (__xn_safe_copy_to_user(ushadow, &shadow, sizeof(shadow))) { + cobalt_sem_destroy_inner(shadow.handle); + return ERR_PTR(-EFAULT); + } + handle = shadow.handle; + break; + + default: + return ERR_PTR(rc); + } + + u = xnmalloc(sizeof(*u)); + if (u == NULL) + return ERR_PTR(-ENOMEM); + + u->sem = sem; + u->mm = current->mm; + u->usem = ushadow; + u->refs = 1; + + xnlock_get_irqsave(&nsem_lock, s); + v = nsem_hash_search(handle, current->mm); + if (v) { + ++v->refs; + xnlock_put_irqrestore(&nsem_lock, s); + xnlock_get_irqsave(&nklock, s); + --sem->refs; + xnlock_put_irqrestore(&nklock, s); + + xnfree(u); + u = v; + } else { + nsem_hash_enter(handle, u); + list_add(&u->link, &cobalt_process_context()->usems); + xnlock_put_irqrestore(&nsem_lock, s); + } + + return u->usem; +} + +static int nsem_close(xnhandle_t handle, struct mm_struct *mm) +{ + struct nsem *u; + spl_t s; + int err; + + xnlock_get_irqsave(&nsem_lock, s); + u = nsem_hash_search(handle, mm); + if (u == NULL) { + err = -ENOENT; + goto err_unlock; + } + + if (--u->refs) { + err = 0; + goto err_unlock; + } + + nsem_hash_remove(u); + list_del(&u->link); + xnlock_put_irqrestore(&nsem_lock, s); + + cobalt_sem_destroy_inner(handle); + + xnfree(u); + return 1; + + err_unlock: + xnlock_put_irqrestore(&nsem_lock, s); + return err; +} + +void cobalt_nsem_unlink_inner(xnhandle_t handle) +{ + if (cobalt_sem_destroy_inner(handle) == -EBUSY) + xnregistry_unlink(xnregistry_key(handle)); +} + +int cobalt_sem_open(struct __shadow_sem __user *__user *u_addr, + const char __user *u_name, + int oflags, mode_t mode, unsigned value) +{ + struct __shadow_sem __user *usm; + struct cobalt_process *cc; + char name[COBALT_MAXNAME + 1]; + long len; + + cc = cobalt_process_context(); + if (cc == NULL) + return -EPERM; + + __xn_get_user(usm, u_addr); + + len = __xn_safe_strncpy_from_user(name, u_name, sizeof(name)); + if (len < 0) + return len; + if (len >= sizeof(name)) + return -ENAMETOOLONG; + if (len == 0) + return -EINVAL; + + usm = nsem_open(usm, name, oflags, mode, value); + if (IS_ERR(usm)) + return PTR_ERR(usm); + + __xn_put_user(usm, u_addr); + + return 0; +} + +int cobalt_sem_close(struct __shadow_sem __user *usm) +{ + struct cobalt_process *cc; + xnhandle_t handle; + + cc = cobalt_process_context(); + if (cc == NULL) + return -EPERM; + + __xn_get_user(handle, &usm->handle); + + return nsem_close(handle, current->mm); +} + +int cobalt_sem_unlink(const char __user *u_name) +{ + char name[COBALT_MAXNAME + 1]; + xnhandle_t handle; + long len; + int rc; + + len = __xn_safe_strncpy_from_user(name, u_name, sizeof(name)); + if (len < 0) + return len; + if (len >= sizeof(name)) + return -ENAMETOOLONG; + + if (name[0] != '/') + return -EINVAL; + + rc = xnregistry_bind(&name[1], XN_NONBLOCK, XN_RELATIVE, &handle); + if (rc == -EWOULDBLOCK) + return -ENOENT; + + cobalt_nsem_unlink_inner(handle); + return 0; +} + +void cobalt_sem_usems_cleanup(struct cobalt_process *cc) +{ + struct nsem *u, *next; + + list_for_each_entry_safe(u, next, &cc->usems, link) { + u->refs = 1; + nsem_close(u->sem->handle, cc->ppd.key.mm); + } +} + +int cobalt_nsem_pkg_init(void) +{ + unsigned i; + + nsem_hash_size = xnregistry_hash_size(); + nsem_hash = kmalloc(nsem_hash_size * sizeof(*nsem_hash), GFP_KERNEL); + if (nsem_hash == NULL) + return -ENOMEM; + + for (i = 0; i < nsem_hash_size; i++) + INIT_HLIST_HEAD(&nsem_hash[i]); + + i = int_sqrt(nsem_hash_size); + mm_shift = 32 - fls(i); + mm_mult = (i << mm_shift) / sizeof(struct mm_struct); + + return 0; +} + +void cobalt_nsem_pkg_cleanup(void) +{ + kfree(nsem_hash); +} diff --git a/kernel/cobalt/posix/sem.c b/kernel/cobalt/posix/sem.c index 9c31fbf..e4ec209 100644 --- a/kernel/cobalt/posix/sem.c +++ b/kernel/cobalt/posix/sem.c @@ -32,7 +32,6 @@ *@{*/ #include <stddef.h> -#include <stdarg.h> #include <linux/err.h> #include "internal.h" #include "thread.h" @@ -41,107 +40,69 @@ #define SEM_NAMED 0x80000000 -struct cobalt_sem { - unsigned int magic; - struct xnsynch synchbase; - /** semq */ - struct list_head link; - struct sem_dat *datp; - int flags; - struct cobalt_kqueues *owningq; -}; - -struct cobalt_usem { - unsigned long uaddr; - unsigned refcnt; - cobalt_assoc_t assoc; -}; - static inline struct cobalt_kqueues *sem_kqueue(struct cobalt_sem *sem) { int pshared = !!(sem->flags & SEM_PSHARED); return cobalt_kqueues(pshared); } -struct cobalt_named_sem { - struct cobalt_sem sembase; /* Has to be the first member. */ - cobalt_node_t nodebase; - union cobalt_sem_union descriptor; -}; - -#define sem2named_sem(saddr) ((struct cobalt_named_sem *)(saddr)) -#define node2sem(naddr) container_of(naddr, struct cobalt_named_sem, nodebase) - -static int sem_destroy_inner(struct cobalt_sem *sem, struct cobalt_kqueues *q) +int cobalt_sem_destroy_inner(xnhandle_t handle) { + struct cobalt_sem *sem; int ret = 0; spl_t s; xnlock_get_irqsave(&nklock, s); + sem = xnregistry_fetch(handle); + if (!cobalt_obj_active(sem, COBALT_SEM_MAGIC, typeof(*sem))) { + ret = -EINVAL; + goto unlock_error; + } + if (--sem->refs) { + ret = -EBUSY; + unlock_error: + xnlock_put_irqrestore(&nklock, s); + return ret; + } + cobalt_mark_deleted(sem); list_del(&sem->link); if (xnsynch_destroy(&sem->synchbase) == XNSYNCH_RESCHED) { xnsched_run(); ret = 1; } - + xnlock_put_irqrestore(&nklock, s); xnheap_free(&xnsys_ppd_get(!!(sem->flags & SEM_PSHARED))->sem_heap, sem->datp); - - if (sem->flags & SEM_NAMED) - xnfree(sem2named_sem(sem)); - else - xnfree(sem); + xnregistry_remove(sem->handle); + + xnfree(sem); return ret; } -/* Called with nklock locked, irq off. */ -static int sem_init_inner(struct cobalt_sem *sem, int flags, - struct sem_dat *datp, unsigned int value) +struct cobalt_sem * +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sm, + int flags, unsigned int value) { + struct list_head *semq; + struct cobalt_sem *sem, *osem; struct cobalt_kqueues *kq; - int pshared, sflags; - - if (value > (unsigned)SEM_VALUE_MAX) - return -EINVAL; - - pshared = !!(flags & SEM_PSHARED); - - sflags = flags & SEM_FIFO ? 0 : XNSYNCH_PRIO; - - sem->magic = COBALT_SEM_MAGIC; - - kq = cobalt_kqueues(pshared); - list_add_tail(&sem->link, &kq->semq); - xnsynch_init(&sem->synchbase, sflags, NULL); - - sem->datp = datp; - atomic_long_set(&datp->value, value); - datp->flags = flags; - sem->flags = flags; - sem->owningq = kq; - - return 0; -} - -static int do_sem_init(struct __shadow_sem *sm, int flags, unsigned int value) -{ - struct list_head *semq, *entry; struct xnsys_ppd *sys_ppd; - struct cobalt_sem *sem; struct sem_dat *datp; - int ret; + int ret, sflags; spl_t s; if ((flags & SEM_PULSE) != 0 && value > 0) - return -EINVAL; + return ERR_PTR(-EINVAL); sem = xnmalloc(sizeof(*sem)); if (sem == NULL) - return -ENOSPC; + return ERR_PTR(-ENOSPC); + + snprintf(sem->name, sizeof(sem->name), "%s", name); sys_ppd = xnsys_ppd_get(!!(flags & SEM_PSHARED)); datp = xnheap_alloc(&sys_ppd->sem_heap, sizeof(*datp)); @@ -153,8 +114,7 @@ static int do_sem_init(struct __shadow_sem *sm, int flags, unsigned int value) xnlock_get_irqsave(&nklock, s); if (sm->magic != COBALT_SEM_MAGIC && - sm->magic != COBALT_NAMED_SEM_MAGIC && - sm->magic == ~COBALT_NAMED_SEM_MAGIC) + sm->magic != COBALT_NAMED_SEM_MAGIC) goto do_init; semq = &cobalt_kqueues(!!(flags & SEM_PSHARED))->semq; @@ -168,30 +128,49 @@ static int do_sem_init(struct __shadow_sem *sm, int flags, unsigned int value) * such semaphore exits, we may assume that other processes * sharing that semaphore won't be able to keep on running. */ - list_for_each(entry, semq) { - if (entry == &sm->sem->link) { - if ((flags & SEM_PSHARED) && - sm->magic == COBALT_SEM_MAGIC) { - sem_destroy_inner(sm->sem, sem_kqueue(sm->sem)); - goto do_init; - } - ret = -EBUSY; - goto err_lock_put; - } + osem = xnregistry_fetch(sm->handle); + if (!cobalt_obj_active(osem, COBALT_SEM_MAGIC, typeof(*osem))) + goto do_init; + + if ((flags & SEM_PSHARED) == 0 || sm->magic != COBALT_SEM_MAGIC) { + ret = -EBUSY; + goto err_lock_put; } + + xnlock_put_irqrestore(&nklock, s); + cobalt_sem_destroy_inner(sm->handle); + xnlock_get_irqsave(&nklock, s); do_init: - ret = sem_init_inner(sem, flags, datp, value); - if (ret) + if (value > (unsigned)SEM_VALUE_MAX) { + ret = -EINVAL; + goto err_lock_put; + } + + ret = xnregistry_enter(sem->name, sem, &sem->handle, NULL); + if (ret < 0) goto err_lock_put; - sm->magic = COBALT_SEM_MAGIC; - sm->sem = sem; + sem->magic = COBALT_SEM_MAGIC; + kq = cobalt_kqueues(!!(flags & SEM_PSHARED)); + list_add_tail(&sem->link, &kq->semq); + sflags = flags & SEM_FIFO ? 0 : XNSYNCH_PRIO; + xnsynch_init(&sem->synchbase, sflags, NULL); + + sem->datp = datp; + atomic_long_set(&datp->value, value); + datp->flags = flags; + sem->flags = flags; + sem->owningq = kq; + sem->refs = name[0] ? 2 : 1; + + sm->magic = name[0] ? COBALT_NAMED_SEM_MAGIC : COBALT_SEM_MAGIC; + sm->handle = sem->handle; sm->datp_offset = xnheap_mapped_offset(&sys_ppd->sem_heap, datp); if (flags & SEM_PSHARED) sm->datp_offset = -sm->datp_offset; xnlock_put_irqrestore(&nklock, s); - return 0; + return sem; err_lock_put: xnlock_put_irqrestore(&nklock, s); @@ -199,7 +178,7 @@ static int do_sem_init(struct __shadow_sem *sm, int flags, unsigned int value) err_free_sem: xnfree(sem); - return ret; + return ERR_PTR(ret); } /** @@ -241,13 +220,17 @@ static int sem_destroy(struct __shadow_sem *sm) spl_t s; xnlock_get_irqsave(&nklock, s); - if (sm->magic != COBALT_SEM_MAGIC - || sm->sem->magic != COBALT_SEM_MAGIC) { + if (sm->magic != COBALT_SEM_MAGIC) { + ret = -EINVAL; + goto error; + } + + sem = xnregistry_fetch(sm->handle); + if (!cobalt_obj_active(sem, COBALT_SEM_MAGIC, typeof(*sem))) { ret = -EINVAL; goto error; } - sem = sm->sem; if (sem_kqueue(sem) != sem->owningq) { ret = -EPERM; goto error; @@ -261,10 +244,9 @@ static int sem_destroy(struct __shadow_sem *sm) warn = sem->flags & SEM_WARNDEL; cobalt_mark_deleted(sm); - cobalt_mark_deleted(sem); xnlock_put_irqrestore(&nklock, s); - ret = sem_destroy_inner(sem, sem_kqueue(sem)); + ret = cobalt_sem_destroy_inner(sem->handle); return warn ? ret : 0; @@ -318,89 +300,6 @@ static int sem_destroy(struct __shadow_sem *sm) * Specification.</a> * */ -sem_t *sem_open(const char *name, int oflags, ...) -{ - struct cobalt_named_sem *named_sem; - struct sem_dat *datp; - cobalt_node_t *node; - unsigned value; - mode_t mode; - va_list ap; - spl_t s; - int err; - - xnlock_get_irqsave(&nklock, s); - err = -cobalt_node_get(&node, name, COBALT_NAMED_SEM_MAGIC, oflags); - xnlock_put_irqrestore(&nklock, s); - - if (err) - goto error; - - if (node) { - named_sem = node2sem(node); - goto got_sem; - } - - named_sem = xnmalloc(sizeof(*named_sem)); - if (named_sem == NULL) { - err = -ENOSPC; - goto error; - } - named_sem->descriptor.shadow_sem.sem = &named_sem->sembase; - - datp = xnheap_alloc(&xnsys_ppd_get(1)->sem_heap, sizeof(*datp)); - if (datp == NULL) { - err = -EAGAIN; - goto err_free_sem; - } - named_sem->descriptor.shadow_sem.datp_offset = - -xnheap_mapped_offset(&xnsys_ppd_get(1)->sem_heap, datp); - - va_start(ap, oflags); - mode = va_arg(ap, int); /* unused */ - value = va_arg(ap, unsigned); - va_end(ap); - - xnlock_get_irqsave(&nklock, s); - err = sem_init_inner(&named_sem->sembase, - SEM_PSHARED|SEM_NAMED, datp, value); - if (err) { - xnlock_put_irqrestore(&nklock, s); - err_free_sem: - xnfree(named_sem); - goto error; - } - - err = -cobalt_node_add(&named_sem->nodebase, name, COBALT_NAMED_SEM_MAGIC); - if (err && err != -EEXIST) - goto err_put_lock; - - if (err == -EEXIST) { - err = -cobalt_node_get(&node, name, COBALT_NAMED_SEM_MAGIC, oflags); - if (err) - goto err_put_lock; - - xnlock_put_irqrestore(&nklock, s); - sem_destroy_inner(&named_sem->sembase, sem_kqueue(&named_sem->sembase)); - named_sem = node2sem(node); - goto got_sem; - } - xnlock_put_irqrestore(&nklock, s); - - got_sem: - /* Set the magic, needed both at creation and when re-opening a semaphore - that was closed but not unlinked. */ - named_sem->descriptor.shadow_sem.magic = COBALT_NAMED_SEM_MAGIC; - - return &named_sem->descriptor.native_sem; - - err_put_lock: - xnlock_put_irqrestore(&nklock, s); - sem_destroy_inner(&named_sem->sembase, sem_kqueue(&named_sem->sembase)); - xnheap_free(&xnsys_ppd_get(1)->sem_heap, datp); - error: - return (sem_t *)ERR_PTR(err); -} /** * Close a named semaphore. @@ -426,48 +325,6 @@ sem_t *sem_open(const char *name, int oflags, ...) * Specification.</a> * */ -int sem_close(struct __shadow_sem *sm) -{ - struct cobalt_named_sem *named_sem; - spl_t s; - int err; - - xnlock_get_irqsave(&nklock, s); - - if (sm->magic != COBALT_NAMED_SEM_MAGIC - || sm->sem->magic != COBALT_SEM_MAGIC) { - err = EINVAL; - goto error; - } - - named_sem = sem2named_sem(sm->sem); - - err = cobalt_node_put(&named_sem->nodebase); - - if (err) - goto error; - - if (cobalt_node_removed_p(&named_sem->nodebase)) { - /* unlink was called, and this semaphore is no longer referenced. */ - cobalt_mark_deleted(sm); - cobalt_mark_deleted(&named_sem->sembase); - xnlock_put_irqrestore(&nklock, s); - - sem_destroy_inner(&named_sem->sembase, cobalt_kqueues(1)); - } else if (!cobalt_node_ref_p(&named_sem->nodebase)) { - /* this semaphore is no longer referenced, but not unlinked. */ - cobalt_mark_deleted(sm); - xnlock_put_irqrestore(&nklock, s); - } else - xnlock_put_irqrestore(&nklock, s); - - return 0; - - error: - xnlock_put_irqrestore(&nklock, s); - - return -err; -} /** * Unlink a named semaphore. @@ -493,39 +350,10 @@ int sem_close(struct __shadow_sem *sm) * Specification.</a> * */ -int sem_unlink(const char *name) -{ - struct cobalt_named_sem *named_sem; - cobalt_node_t *node; - spl_t s; - int err; - - xnlock_get_irqsave(&nklock, s); - - err = cobalt_node_remove(&node, name, COBALT_NAMED_SEM_MAGIC); - if (err) - goto error; - - named_sem = node2sem(node); - - if (cobalt_node_removed_p(&named_sem->nodebase)) { - xnlock_put_irqrestore(&nklock, s); - - sem_destroy_inner(&named_sem->sembase, cobalt_kqueues(1)); - } else - xnlock_put_irqrestore(&nklock, s); - - return 0; - - error: - xnlock_put_irqrestore(&nklock, s); - - return -err; -} static inline int sem_trywait_internal(struct cobalt_sem *sem) { - if (sem->magic != COBALT_SEM_MAGIC) + if (sem == NULL || sem->magic != COBALT_SEM_MAGIC) return -EINVAL; #if XENO_DEBUG(COBALT) @@ -560,22 +388,23 @@ static inline int sem_trywait_internal(struct cobalt_sem *sem) * Specification.</a> * */ -static int sem_trywait(struct cobalt_sem *sem) +static int sem_trywait(xnhandle_t handle) { int err; spl_t s; xnlock_get_irqsave(&nklock, s); - err = sem_trywait_internal(sem); + err = sem_trywait_internal(xnregistry_fetch(handle)); xnlock_put_irqrestore(&nklock, s); return err; } static inline int -sem_timedwait_internal(struct cobalt_sem *sem, int timed, +sem_timedwait_internal(xnhandle_t handle, int timed, const struct timespec __user *u_ts) { + struct cobalt_sem *sem; struct timespec ts; xntmode_t tmode; int ret, info; @@ -583,6 +412,8 @@ sem_timedwait_internal(struct cobalt_sem *sem, int timed, xnlock_get_irqsave(&nklock, s); + sem = xnregistry_fetch(handle); + ret = sem_trywait_internal(sem); if (ret != -EAGAIN) { xnlock_put_irqrestore(&nklock, s); @@ -651,9 +482,9 @@ out: * Specification.</a> * */ -static int sem_wait(struct cobalt_sem *sem) +static int sem_wait(xnhandle_t handle) { - return sem_timedwait_internal(sem, 0, NULL); + return sem_timedwait_internal(handle, 0, NULL); } /** @@ -690,15 +521,15 @@ static int sem_wait(struct cobalt_sem *sem) * Specification.</a> * */ -static int sem_timedwait(struct cobalt_sem *sem, +static int sem_timedwait(xnhandle_t handle, const struct timespec __user *abs_timeout) { - return sem_timedwait_internal(sem, 1, abs_timeout); + return sem_timedwait_internal(handle, 1, abs_timeout); } int sem_post_inner(struct cobalt_sem *sem, struct cobalt_kqueues *ownq, int bcast) { - if (sem->magic != COBALT_SEM_MAGIC) + if (!sem || sem->magic != COBALT_SEM_MAGIC) return -EINVAL; #if XENO_DEBUG(COBALT) @@ -751,12 +582,14 @@ int sem_post_inner(struct cobalt_sem *sem, struct cobalt_kqueues *ownq, int bcas * Specification.</a> * */ -static int sem_post(struct cobalt_sem *sm) +static int sem_post(xnhandle_t handle) { + struct cobalt_sem *sm; int ret; spl_t s; xnlock_get_irqsave(&nklock, s); + sm = xnregistry_fetch(handle); ret = sem_post_inner(sm, sm->owningq, 0); xnlock_put_irqrestore(&nklock, s); @@ -791,13 +624,16 @@ static int sem_post(struct cobalt_sem *sm) * Specification.</a> * */ -int sem_getvalue(struct cobalt_sem *sem, int *value) +static int sem_getvalue(xnhandle_t handle, int *value) { + struct cobalt_sem *sem; spl_t s; xnlock_get_irqsave(&nklock, s); - if (sem->magic != COBALT_SEM_MAGIC) { + sem = xnregistry_fetch(handle); + + if (sem == NULL || sem->magic != COBALT_SEM_MAGIC) { xnlock_put_irqrestore(&nklock, s); return -EINVAL; } @@ -819,63 +655,63 @@ int sem_getvalue(struct cobalt_sem *sem, int *value) int cobalt_sem_init(struct __shadow_sem __user *u_sem, int pshared, unsigned value) { struct __shadow_sem sm; - int err; + struct cobalt_sem *sem; if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) return -EFAULT; - err = do_sem_init(&sm, pshared ? SEM_PSHARED : 0, value); - if (err < 0) - return err; + sem = cobalt_sem_init_inner("", &sm, pshared ? SEM_PSHARED : 0, value); + if (IS_ERR(sem)) + return PTR_ERR(sem); return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); } int cobalt_sem_post(struct __shadow_sem __user *u_sem) { - struct cobalt_sem *sm; + xnhandle_t handle; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); - return sem_post(sm); + return sem_post(handle); } int cobalt_sem_wait(struct __shadow_sem __user *u_sem) { - struct cobalt_sem *sm; + xnhandle_t handle; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); - return sem_wait(sm); + return sem_wait(handle); } int cobalt_sem_timedwait(struct __shadow_sem __user *u_sem, struct timespec __user *u_ts) { - struct cobalt_sem *sm; + xnhandle_t handle; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); - return sem_timedwait(sm, u_ts); + return sem_timedwait(handle, u_ts); } int cobalt_sem_trywait(struct __shadow_sem __user *u_sem) { - struct cobalt_sem *sm; + xnhandle_t handle; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); - return sem_trywait(sm); + return sem_trywait(handle); } int cobalt_sem_getvalue(struct __shadow_sem __user *u_sem, int __user *u_sval) { - struct cobalt_sem *sm; + xnhandle_t handle; int err, sval; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); - err = sem_getvalue(sm, &sval); + err = sem_getvalue(handle, &sval); if (err < 0) return err; @@ -897,154 +733,11 @@ int cobalt_sem_destroy(struct __shadow_sem __user *u_sem) return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)) ?: err; } -int cobalt_sem_open(unsigned long __user *u_addr, - const char __user *u_name, - int oflags, mode_t mode, unsigned value) -{ - struct cobalt_process *cc; - char name[COBALT_MAXNAME]; - struct __shadow_sem *sm; - struct cobalt_usem *usm; - cobalt_assoc_t *assoc; - unsigned long uaddr; - long len; - int err; - spl_t s; - - cc = cobalt_process_context(); - if (cc == NULL) - return -EPERM; - - if (__xn_safe_copy_from_user(&uaddr, u_addr, sizeof(uaddr))) - return -EFAULT; - - len = __xn_safe_strncpy_from_user(name, u_name, sizeof(name)); - if (len < 0) - return len; - if (len >= sizeof(name)) - return -ENAMETOOLONG; - if (len == 0) - return -EINVAL; - - if (!(oflags & O_CREAT)) - sm = &((union cobalt_sem_union *)sem_open(name, oflags))->shadow_sem; - else - sm = &((union cobalt_sem_union *)sem_open(name, oflags, mode, value))->shadow_sem; - - if (IS_ERR(sm)) - return PTR_ERR(sm); - - xnlock_get_irqsave(&cobalt_assoc_lock, s); - - assoc = cobalt_assoc_lookup(&cc->usems, (u_long)sm->sem); - if (assoc) { - usm = container_of(assoc, struct cobalt_usem, assoc); - ++usm->refcnt; - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - goto got_usm; - } - - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - - usm = xnmalloc(sizeof(*usm)); - if (usm == NULL) { - sem_close(sm); - return -ENOSPC; - } - - usm->uaddr = uaddr; - usm->refcnt = 1; - - xnlock_get_irqsave(&cobalt_assoc_lock, s); - - assoc = cobalt_assoc_lookup(&cc->usems, (u_long)sm->sem); - if (assoc) { - container_of(assoc, struct cobalt_usem, assoc)->refcnt++; - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - xnfree(usm); - usm = container_of(assoc, struct cobalt_usem, assoc); - goto got_usm; - } - - cobalt_assoc_insert(&cc->usems, &usm->assoc, (u_long)sm->sem); - - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - - got_usm: - - if (usm->uaddr == uaddr) - /* First binding by this process. */ - err = __xn_safe_copy_to_user((void __user *)usm->uaddr, - sm, sizeof(*sm)); - else - /* Semaphore already bound by this process in user-space. */ - err = __xn_safe_copy_to_user(u_addr, - &usm->uaddr, sizeof(*u_addr)); - - return err; -} - -int cobalt_sem_close(unsigned long uaddr, int __user *u_closed) -{ - struct cobalt_process *cc; - struct cobalt_usem *usm; - struct __shadow_sem sm; - cobalt_assoc_t *assoc; - int closed = 0, err; - spl_t s; - - cc = cobalt_process_context(); - if (cc == NULL) - return -EPERM; - - if (__xn_safe_copy_from_user(&sm, (void __user *)uaddr, sizeof(sm))) - return -EFAULT; - - xnlock_get_irqsave(&cobalt_assoc_lock, s); - - assoc = cobalt_assoc_lookup(&cc->usems, (u_long)sm.sem); - if (assoc == NULL) { - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - return -EINVAL; - } - - usm = container_of(assoc, struct cobalt_usem, assoc); - - err = sem_close(&sm); - - if (!err && (closed = (--usm->refcnt == 0))) - cobalt_assoc_remove(&cc->usems, (u_long)sm.sem); - - xnlock_put_irqrestore(&cobalt_assoc_lock, s); - - if (err < 0) - return err; - - if (closed) - xnfree(usm); - - return __xn_safe_copy_to_user(u_closed, &closed, sizeof(*u_closed)); -} - -int cobalt_sem_unlink(const char __user *u_name) -{ - char name[COBALT_MAXNAME]; - long len; - - len = __xn_safe_strncpy_from_user(name, u_name, sizeof(name)); - if (len < 0) - return len; - if (len >= sizeof(name)) - return -ENAMETOOLONG; - - return sem_unlink(name); -} - int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, int flags, unsigned value) { struct __shadow_sem sm; - int err; + struct cobalt_sem *sem; if (__xn_safe_copy_from_user(&sm, u_sem, sizeof(sm))) return -EFAULT; @@ -1053,9 +746,9 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, SEM_WARNDEL|SEM_RAWCLOCK|SEM_NOBUSYDEL)) return -EINVAL; - err = do_sem_init(&sm, flags, value); - if (err < 0) - return err; + sem = cobalt_sem_init_inner("", &sm, flags, value); + if (IS_ERR(sem)) + return PTR_ERR(sem); return __xn_safe_copy_to_user(u_sem, &sm, sizeof(*u_sem)); } @@ -1063,41 +756,23 @@ int cobalt_sem_init_np(struct __shadow_sem __user *u_sem, int cobalt_sem_broadcast_np(struct __shadow_sem __user *u_sem) { struct cobalt_sem *sm; + xnhandle_t handle; spl_t s; int err; - __xn_get_user(sm, &u_sem->sem); + __xn_get_user(handle, &u_sem->handle); xnlock_get_irqsave(&nklock, s); + sm = xnregistry_fetch(handle); err = sem_post_inner(sm, sm->owningq, 1); xnlock_put_irqrestore(&nklock, s); return err; } -static void usem_cleanup(cobalt_assoc_t *assoc) -{ - struct cobalt_usem *usem = container_of(assoc, struct cobalt_usem, assoc); - struct cobalt_sem *sem = (struct cobalt_sem *)cobalt_assoc_key(assoc); - struct cobalt_named_sem *nsem = sem2named_sem(sem); - -#if XENO_DEBUG(COBALT) - printk(XENO_INFO "closing Cobalt semaphore \"%s\"\n", - nsem->nodebase.name); -#endif /* XENO_DEBUG(COBALT) */ - sem_close(&nsem->descriptor.shadow_sem); - xnfree(usem); -} - -void cobalt_sem_usems_cleanup(struct cobalt_process *cc) -{ - cobalt_assocq_destroy(&cc->usems, &usem_cleanup); -} - void cobalt_semq_cleanup(struct cobalt_kqueues *q) { struct cobalt_sem *sem, *tmp; - cobalt_node_t *node; spl_t s; xnlock_get_irqsave(&nklock, s); @@ -1110,23 +785,20 @@ void cobalt_semq_cleanup(struct cobalt_kqueues *q) #if XENO_DEBUG(COBALT) if (sem->flags & SEM_NAMED) printk(XENO_INFO "unlinking Cobalt semaphore \"%s\"\n", - sem2named_sem(sem)->nodebase.name); - else + xnregistry_key(sem->handle)); + else printk(XENO_INFO "deleting Cobalt semaphore %p\n", sem); #endif /* XENO_DEBUG(COBALT) */ - xnlock_get_irqsave(&nklock, s); if (sem->flags & SEM_NAMED) - cobalt_node_remove(&node, - sem2named_sem(sem)->nodebase.name, - COBALT_NAMED_SEM_MAGIC); - xnlock_put_irqrestore(&nklock, s); - sem_destroy_inner(sem, q); + cobalt_nsem_unlink_inner(sem->handle); + cobalt_sem_destroy_inner(sem->handle); xnlock_get_irqsave(&nklock, s); } out: xnlock_put_irqrestore(&nklock, s); } + void cobalt_sem_pkg_init(void) { INIT_LIST_HEAD(&cobalt_global_kqueues.semq); diff --git a/kernel/cobalt/posix/sem.h b/kernel/cobalt/posix/sem.h index ac37ffd..7667976 100644 --- a/kernel/cobalt/posix/sem.h +++ b/kernel/cobalt/posix/sem.h @@ -23,9 +23,21 @@ #include <cobalt/kernel/thread.h> #include <cobalt/kernel/registry.h> -struct cobalt_sem; struct cobalt_process; +struct cobalt_sem { + unsigned int magic; + struct xnsynch synchbase; + /** semq */ + struct list_head link; + struct sem_dat *datp; + int flags; + struct cobalt_kqueues *owningq; + xnhandle_t handle; + unsigned refs; + char name[COBALT_MAXNAME]; +}; + /* Copied from Linuxthreads semaphore.h. */ struct _sem_fastlock { @@ -45,12 +57,15 @@ typedef struct #define SEM_VALUE_MAX (INT_MAX) #define SEM_FAILED NULL -void cobalt_sem_usems_cleanup(struct cobalt_process *cc); +struct cobalt_sem * +cobalt_sem_init_inner(const char *name, struct __shadow_sem *sem, + int flags, unsigned value); -int sem_getvalue(struct cobalt_sem *sem, int *value); +int cobalt_sem_destroy_inner(xnhandle_t handle); -int sem_post_inner(struct cobalt_sem *sem, - struct cobalt_kqueues *ownq, int bcast); +void cobalt_nsem_unlink_inner(xnhandle_t handle); + +void cobalt_sem_usems_cleanup(struct cobalt_process *cc); int cobalt_sem_init(struct __shadow_sem __user *u_sem, int pshared, unsigned value); @@ -69,11 +84,11 @@ int cobalt_sem_getvalue(struct __shadow_sem __user *u_sem, int cobalt_sem_destroy(struct __shadow_sem __user *u_sem); -int cobalt_sem_open(unsigned long __user *u_addr, +int cobalt_sem_open(struct __shadow_sem __user *__user *u_addr, const char __user *u_name, int oflags, mode_t mode, unsigned value); -int cobalt_sem_close(unsigned long uaddr, int __user *u_closed); +int cobalt_sem_close(struct __shadow_sem __user *usm); int cobalt_sem_unlink(const char __user *u_name); @@ -88,4 +103,8 @@ void cobalt_sem_pkg_init(void); void cobalt_sem_pkg_cleanup(void); +int cobalt_nsem_pkg_init(void); + +void cobalt_nsem_pkg_cleanup(void); + #endif /* !_COBALT_POSIX_SEM_H */ diff --git a/lib/cobalt/semaphore.c b/lib/cobalt/semaphore.c index fde4bfd..88535a8 100644 --- a/lib/cobalt/semaphore.c +++ b/lib/cobalt/semaphore.c @@ -23,6 +23,7 @@ #include <pthread.h> /* For pthread_setcanceltype. */ #include <semaphore.h> #include <asm/xenomai/syscall.h> +#include <cobalt/uapi/sem.h> #include "internal.h" static inline struct sem_dat *sem_get_datp(struct __shadow_sem *shadow) @@ -262,24 +263,22 @@ COBALT_IMPL(sem_t *, sem_open, (const char *name, int oflags, ...)) COBALT_IMPL(int, sem_close, (sem_t *sem)) { struct __shadow_sem *_sem = &((union cobalt_sem_union *)sem)->shadow_sem; - int err, closed; + int err; if (_sem->magic != COBALT_NAMED_SEM_MAGIC) { errno = EINVAL; return -1; } - err = -XENOMAI_SKINCALL2(__cobalt_muxid, - sc_cobalt_sem_close, _sem, &closed); - - if (!err) { - if (closed) - free(sem); - return 0; + err = XENOMAI_SKINCALL1(__cobalt_muxid, sc_cobalt_sem_close, _sem); + if (err < 0) { + errno = -err; + return -1; } + if (err) + free(sem); - errno = err; - return -1; + return 0; } COBALT_IMPL(int, sem_unlink, (const char *name)) _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git