Module: xenomai-forge
Branch: next
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

Reply via email to