Module: xenomai-gch
Branch: for-forge
Commit: 6283f90241c5653dd9663a06c3847bbcba99651a
URL:    
http://git.xenomai.org/?p=xenomai-gch.git;a=commit;h=6283f90241c5653dd9663a06c3847bbcba99651a

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Sat Dec 28 21:57:41 2013 +0100

cobalt: factor per-process ids table code

already used for named semaphores and file descriptors, and going to be used
for timers.

---

 include/cobalt/kernel/fd.h       |    7 ++-
 include/cobalt/kernel/id_table.h |   45 ++++++++++++++++++
 include/cobalt/kernel/registry.h |    2 +-
 kernel/cobalt/Makefile           |    1 +
 kernel/cobalt/fd.c               |   84 ++++++++++------------------------
 kernel/cobalt/id_table.c         |   93 ++++++++++++++++++++++++++++++++++++++
 kernel/cobalt/posix/nsem.c       |   65 ++++++--------------------
 kernel/cobalt/registry.c         |    6 +--
 8 files changed, 184 insertions(+), 119 deletions(-)

diff --git a/include/cobalt/kernel/fd.h b/include/cobalt/kernel/fd.h
index 4f004f5..6793640 100644
--- a/include/cobalt/kernel/fd.h
+++ b/include/cobalt/kernel/fd.h
@@ -20,6 +20,7 @@
 #define _COBALT_KERNEL_FD_H
 
 #include <linux/types.h>
+#include <cobalt/kernel/id_table.h>
 
 struct xnfd;
 struct xnselector;
@@ -43,11 +44,9 @@ struct xnfd_ops {
 
 struct xnfd {
        unsigned magic;
-       struct mm_struct *mm;
-       int ufd;
+       struct xnid xnid;
        struct xnfd_ops *ops;
        unsigned refs;
-       struct hlist_node hlink; /* Link in global hash */
        struct list_head link;   /* Link in per-process queue */
 };
 
@@ -72,7 +71,7 @@ int xnfd_close(int ufd, struct mm_struct *mm, unsigned magic);
 
 static inline int xnfd_getfd(struct xnfd *xnfd)
 {
-       return xnfd->ufd;
+       return xnfd->xnid.id;
 }
 
 int xnfd_valid_p(int ufd, struct mm_struct *mm);
diff --git a/include/cobalt/kernel/id_table.h b/include/cobalt/kernel/id_table.h
new file mode 100644
index 0000000..ea9256b
--- /dev/null
+++ b/include/cobalt/kernel/id_table.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef _COBALT_KERNEL_ID_TABLE_H
+#define _COBALT_KERNEL_ID_TABLE_H
+
+struct xnid_table {
+       struct hlist_head *hash;
+       unsigned mm_mult, mm_shift, hash_size;
+};
+
+struct xnid {
+       struct mm_struct *mm;
+       unsigned long id;
+       struct hlist_node hlink;
+};
+
+int xnid_table_init(struct xnid_table *t, unsigned size);
+
+int xnid_enter(struct xnid_table *t, struct xnid *xnid, 
+       struct mm_struct *mm, unsigned long id);
+
+struct xnid *xnid_fetch(struct xnid_table *t, 
+                       struct mm_struct *mm, unsigned long id);
+
+int xnid_remove(struct xnid_table *t, struct xnid *xnid);
+
+void xnid_table_cleanup(struct xnid_table *t);
+
+#endif /* _COBALT_KERNEL_ID_TABLE_H */
diff --git a/include/cobalt/kernel/registry.h b/include/cobalt/kernel/registry.h
index fea07ca..8936f3d 100644
--- a/include/cobalt/kernel/registry.h
+++ b/include/cobalt/kernel/registry.h
@@ -192,7 +192,7 @@ unsigned long xnregistry_put(xnhandle_t handle);
 
 int xnregistry_unlink(const char *key);
 
-unsigned xnregistry_hash_size(void);
+unsigned xnregistry_hash_size(unsigned size);
 
 extern struct xnpnode_ops xnregistry_vfsnap_ops;
 
diff --git a/kernel/cobalt/Makefile b/kernel/cobalt/Makefile
index e5e3355..7fdcc18 100644
--- a/kernel/cobalt/Makefile
+++ b/kernel/cobalt/Makefile
@@ -7,6 +7,7 @@ xenomai-y :=    apc.o           \
                clock.o         \
                fd.o            \
                heap.o          \
+               id_table.o      \
                init.o          \
                intr.o          \
                lock.o          \
diff --git a/kernel/cobalt/fd.c b/kernel/cobalt/fd.c
index c350492..13e9239 100644
--- a/kernel/cobalt/fd.c
+++ b/kernel/cobalt/fd.c
@@ -25,28 +25,16 @@
 #include <cobalt/kernel/fd.h>
 #include <cobalt/kernel/ppd.h>
 
-static struct hlist_head *xnfd_hash;
+static struct xnid_table xnfd_table;
 DEFINE_XNLOCK(xnfd_lock);
-static unsigned mm_mult, mm_shift, xnfd_hash_size;
-
-static unsigned __attribute__((pure))
-xnfd_crunch(int ufd, struct mm_struct *mm)
-{
-       unsigned long hash = (unsigned long)mm;
-       hash = ufd + (((unsigned long long)hash * mm_mult) >> mm_shift);
-       return hash % xnfd_hash_size;
-}
 
 static struct xnfd *xnfd_hash_search(int ufd, struct mm_struct *mm)
 {
-       unsigned bucket = xnfd_crunch(ufd, mm);
-       struct xnfd *xnfd;
-       
-       hlist_for_each_entry(xnfd, &xnfd_hash[bucket], hlink)
-               if (xnfd->ufd == ufd && xnfd->mm == mm)
-                       return xnfd;
+       struct xnid *i = xnid_fetch(&xnfd_table, mm, ufd);
+       if (i == NULL)
+               return NULL;
        
-       return NULL;
+       return container_of(i, struct xnfd, xnid);
 }
 
 static int enosys(void)
@@ -66,7 +54,7 @@ static void nop_destroy(struct xnfd *xnfd)
 int xnfd_enter(struct xnfd *xnfd, unsigned magic, int ufd, 
        struct xnsys_ppd *p, struct xnfd_ops *ops)
 {
-       unsigned bucket;
+       struct mm_struct *mm;
        spl_t s;
        int err;
 
@@ -109,21 +97,14 @@ int xnfd_enter(struct xnfd *xnfd, unsigned magic, int ufd,
                ops->destroy = nop_destroy;
 
        xnfd->magic = magic;
-       xnfd->mm = p != &__xnsys_global_ppd ? p->ppd.key.mm : &init_mm;
-       xnfd->ufd = ufd;
        xnfd->refs = 1;
        xnfd->ops = ops;
-       bucket = xnfd_crunch(ufd, xnfd->mm);
+       mm = p != &__xnsys_global_ppd ? p->ppd.key.mm : &init_mm;
        
        xnlock_get_irqsave(&xnfd_lock, s);
-#if XENO_DEBUG(NUCLEUS)
-       if (xnfd_hash_search(ufd, xnfd->mm)) {
-               xnlock_put_irqrestore(&xnfd_lock, s);
-               err = -EBUSY;
+       err = xnid_enter(&xnfd_table, &xnfd->xnid, mm, ufd);
+       if (err < 0)
                goto err;
-       }
-#endif
-       hlist_add_head(&xnfd->hlink, &xnfd_hash[bucket]);
        list_add(&xnfd->link, &p->fds);
        xnlock_put_irqrestore(&xnfd_lock, s);
        
@@ -154,20 +135,28 @@ struct xnfd *xnfd_get(int ufd, struct mm_struct *mm, 
unsigned magic)
        return res;
 }
 
-static void xnfd_put_inner(struct xnfd *xnfd, spl_t s)
+static int xnfd_put_inner(struct xnfd *xnfd, spl_t s)
 {
        int destroy;
 
        destroy = --xnfd->refs == 0;
        if (destroy) {
-               if (xnfd->magic)
-                       hlist_del(&xnfd->hlink);
+               if (xnfd->magic) {
+                       int err = xnid_remove(&xnfd_table, &xnfd->xnid);
+                       if (err < 0) {
+                               ++xnfd->refs;
+                               xnlock_put_irqrestore(&xnfd_lock, s);
+                               return err;
+                       }
+               }
                list_del(&xnfd->link);
        }
        xnlock_put_irqrestore(&xnfd_lock, s);
        
        if (destroy)
                xnfd->ops->destroy(xnfd);
+
+       return 0;
 }
 
 int xnfd_put(struct xnfd *xnfd)
@@ -175,16 +164,7 @@ int xnfd_put(struct xnfd *xnfd)
        spl_t s;
        
        xnlock_get_irqsave(&xnfd_lock, s);
-#if XENO_DEBUG(NUCLEUS)
-       if (xnfd_hash_search(xnfd->ufd, xnfd->mm) != xnfd) {
-               xnlock_put_irqrestore(&xnfd_lock, s);
-               return -EBADF;
-       }
-#endif
-
-       xnfd_put_inner(xnfd, s);
-
-       return 0;
+       return xnfd_put_inner(xnfd, s);
 }
 
 int xnfd_ioctl(int fd, struct mm_struct *mm, 
@@ -259,7 +239,7 @@ int xnfd_close(int ufd, struct mm_struct *mm, unsigned 
magic)
        }
 
        xnfd->magic = 0;
-       hlist_del(&xnfd->hlink);
+       xnid_remove(&xnfd_table, &xnfd->xnid);
        
        xnfd_put_inner(xnfd, s);
 
@@ -320,26 +300,10 @@ void xnfd_cleanup(struct xnsys_ppd *p)
 
 int xnfd_mount(void)
 {
-       unsigned i;
-       
-       xnfd_hash_size = xnregistry_hash_size();
-       xnfd_hash = kmalloc(xnfd_hash_size * sizeof(*xnfd_hash), GFP_KERNEL);
-       if (xnfd_hash == NULL)
-               return -ENOMEM;
-       
-       for (i = 0; i < xnfd_hash_size; i++)
-               INIT_HLIST_HEAD(&xnfd_hash[i]);
-
-       i = int_sqrt(xnfd_hash_size);
-       mm_shift = 32 - fls(i);
-       mm_mult = (i << mm_shift) / sizeof(struct mm_struct);
-       
-       INIT_LIST_HEAD(&__xnsys_global_ppd.fds);
-
-       return 0;
+       return xnid_table_init(&xnfd_table, CONFIG_XENO_OPT_REGISTRY_NRSLOTS);
 }
 
 void xnfd_umount(void)
 {
-       kfree(xnfd_hash);
+       xnid_table_cleanup(&xnfd_table);
 }
diff --git a/kernel/cobalt/id_table.c b/kernel/cobalt/id_table.c
new file mode 100644
index 0000000..f69ab44
--- /dev/null
+++ b/kernel/cobalt/id_table.c
@@ -0,0 +1,93 @@
+/*
+ * 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/err.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <cobalt/kernel/registry.h>
+#include <cobalt/kernel/id_table.h>
+
+int xnid_table_init(struct xnid_table *t, unsigned size)
+{
+       unsigned i;
+       
+       t->hash_size = xnregistry_hash_size(size);
+       t->hash = kmalloc(t->hash_size * sizeof(*t->hash), GFP_KERNEL);
+       if (t->hash == NULL)
+               return -ENOMEM;
+       
+       for (i = 0; i < t->hash_size; i++)
+               INIT_HLIST_HEAD(&t->hash[i]);
+       
+       i = int_sqrt(t->hash_size);
+       t->mm_shift = 32 - fls(i);
+       t->mm_mult = (i << t->mm_shift) / sizeof(struct mm_struct);
+       return 0;
+}
+
+static unsigned __attribute__((pure))
+xnid_crunch(struct xnid_table *t, unsigned long id, struct mm_struct *mm)
+{
+       unsigned long hash = (unsigned long)mm;
+       hash = id + (((unsigned long long)hash * t->mm_mult) >> t->mm_shift);
+       return hash % t->hash_size;
+}
+
+struct xnid *xnid_fetch(struct xnid_table *t, 
+                       struct mm_struct *mm, unsigned long id)
+{
+       unsigned bucket = xnid_crunch(t, id, mm);
+       struct xnid *i;
+       
+       hlist_for_each_entry(i, &t->hash[bucket], hlink)
+               if (i->id == id && i->mm == mm)
+                       return i;
+       
+       return NULL;
+}
+
+int xnid_enter(struct xnid_table *t, struct xnid *xnid, 
+       struct mm_struct *mm, unsigned long id)
+{
+       unsigned bucket = xnid_crunch(t, id, mm);
+#if XENO_DEBUG(NUCLEUS)
+       if (xnid_fetch(t, mm, id))
+               return -EBUSY;
+#endif
+       xnid->mm = mm;
+       xnid->id = id;
+       hlist_add_head(&xnid->hlink, &t->hash[bucket]);
+       return 0;
+}
+
+int xnid_remove(struct xnid_table *t, struct xnid *xnid)
+{
+#if XENO_DEBUG(NUCLEUS)
+       if (xnid_fetch(t, xnid->mm, xnid->id) != xnid)
+               return -EBADF;
+#endif
+       hlist_del(&xnid->hlink);
+       return 0;
+}
+
+void xnid_table_cleanup(struct xnid_table *t)
+{
+       kfree(t->hash);
+       t->hash = NULL;
+}
diff --git a/kernel/cobalt/posix/nsem.c b/kernel/cobalt/posix/nsem.c
index c19faaf..a5f05e1 100644
--- a/kernel/cobalt/posix/nsem.c
+++ b/kernel/cobalt/posix/nsem.c
@@ -18,55 +18,33 @@
 
 #include <linux/list.h>
 #include <linux/err.h>
+#include <cobalt/kernel/id_table.h>
 #include <cobalt/kernel/lock.h>
 #include <cobalt/kernel/heap.h>
 #include "internal.h"
 #include "sem.h"
 
-static struct hlist_head *nsem_hash;
+static struct xnid_table nsem_table;
 DEFINE_XNLOCK(nsem_lock);
-static unsigned mm_mult, mm_shift, nsem_hash_size;
 
 struct nsem {
        struct cobalt_sem *sem;
-       struct mm_struct *mm;
+       struct xnid xnid;
        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);
+       struct xnid *i;
+       
+       i = xnid_fetch(&nsem_table, mm, handle);
+       if (i == NULL)
+               return NULL;
 
-       hlist_add_head(&nsem->hlink, &nsem_hash[bucket]);
-}
-
-static void nsem_hash_remove(struct nsem *u)
-{
-       hlist_del(&u->hlink);
+       return container_of(i, struct nsem, xnid);
 }
 
 static struct __shadow_sem __user *
@@ -146,7 +124,6 @@ nsem_open(struct __shadow_sem __user *ushadow, const char 
*name,
                return ERR_PTR(-ENOMEM);
 
        u->sem = sem;
-       u->mm = current->mm;
        u->usem = ushadow;
        u->refs = 1;
 
@@ -162,7 +139,7 @@ nsem_open(struct __shadow_sem __user *ushadow, const char 
*name,
                xnfree(u);
                u = v;
        } else {
-               nsem_hash_enter(handle, u);
+               xnid_enter(&nsem_table, &u->xnid, current->mm, handle);
                list_add(&u->link, &cobalt_process_context()->usems);
                xnlock_put_irqrestore(&nsem_lock, s);
        }
@@ -179,7 +156,7 @@ static int nsem_close(xnhandle_t handle, struct mm_struct 
*mm)
        xnlock_get_irqsave(&nsem_lock, s);
        u = nsem_hash_search(handle, mm);
        if (u == NULL) {
-               err = -ENOENT;
+               err = -EINVAL;
                goto err_unlock;
        }
        
@@ -188,7 +165,7 @@ static int nsem_close(xnhandle_t handle, struct mm_struct 
*mm)
                goto err_unlock;
        }
        
-       nsem_hash_remove(u);
+       xnid_remove(&nsem_table, &u->xnid);
        list_del(&u->link);
        xnlock_put_irqrestore(&nsem_lock, s);
                        
@@ -290,24 +267,10 @@ void cobalt_sem_usems_cleanup(struct cobalt_process *cc)
 
 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;
+       return xnid_table_init(&nsem_table, CONFIG_XENO_OPT_REGISTRY_NRSLOTS);
 }
 
 void cobalt_nsem_pkg_cleanup(void)
 {
-       kfree(nsem_hash);
+       xnid_table_cleanup(&nsem_table);
 }
diff --git a/kernel/cobalt/registry.c b/kernel/cobalt/registry.c
index 79a9afe..6265817 100644
--- a/kernel/cobalt/registry.c
+++ b/kernel/cobalt/registry.c
@@ -93,7 +93,7 @@ static struct xnvfile_regular usage_vfile = {
 
 #endif /* CONFIG_XENO_OPT_VFILE */
 
-unsigned xnregistry_hash_size(void)
+unsigned xnregistry_hash_size(unsigned size)
 {
        static const int primes[] = {
                101, 211, 307, 401, 503, 601,
@@ -104,7 +104,7 @@ unsigned xnregistry_hash_size(void)
 ((n) < sizeof(primes) / sizeof(int) ? \
  (n) : sizeof(primes) / sizeof(int) - 1)
 
-       return primes[obj_hash_max(CONFIG_XENO_OPT_REGISTRY_NRSLOTS / 100)];
+       return primes[obj_hash_max((size + 99) / 100)];
 }
 
 int xnregistry_init(void)
@@ -148,7 +148,7 @@ int xnregistry_init(void)
        list_get_entry(&free_object_list, struct xnobject, link);
        nr_active_objects = 1;
 
-       nr_object_entries = xnregistry_hash_size();
+       nr_object_entries = 
xnregistry_hash_size(CONFIG_XENO_OPT_REGISTRY_NRSLOTS);
        object_index = kmalloc(sizeof(*object_index) *
                                      nr_object_entries, GFP_KERNEL);
 


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to