Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Change the way semid_t values are chosen. Instead of us...



details:   https://anonhg.NetBSD.org/src/rev/4b6ee64576e1
branches:  trunk
changeset: 588876:4b6ee64576e1
user:      cube <cube%NetBSD.org@localhost>
date:      Sun Mar 05 00:49:19 2006 +0000

description:
Change the way semid_t values are chosen.  Instead of using kernel
addresses, use a uint32_t counter and the machinery to properly use it.
That makes the ksem_* system calls friendly for COMPAT_NETBSD32.

OK'd by thorpej@.

diffstat:

 sys/kern/uipc_sem.c |  89 +++++++++++++++++++++++++++++++++++++++++++---------
 sys/sys/ksem.h      |   6 ++-
 2 files changed, 78 insertions(+), 17 deletions(-)

diffs (268 lines):

diff -r 4d0918b0f4c5 -r 4b6ee64576e1 sys/kern/uipc_sem.c
--- a/sys/kern/uipc_sem.c       Sun Mar 05 00:32:43 2006 +0000
+++ b/sys/kern/uipc_sem.c       Sun Mar 05 00:49:19 2006 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uipc_sem.c,v 1.12 2005/12/24 19:12:23 perry Exp $      */
+/*     $NetBSD: uipc_sem.c,v 1.13 2006/03/05 00:49:19 cube Exp $       */
 
 /*-
  * Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -63,7 +63,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.12 2005/12/24 19:12:23 perry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.13 2006/03/05 00:49:19 cube Exp $");
 
 #include "opt_posix.h"
 
@@ -89,8 +89,10 @@
 
 #define SEM_MAX_NAMELEN        14
 #define SEM_VALUE_MAX (~0U)
+#define SEM_HASHTBL_SIZE 13
 
-#define SEM_TO_ID(x)   ((intptr_t)(x))
+#define SEM_TO_ID(x)   (((x)->ks_id))
+#define SEM_HASH(id)   ((id) % SEM_HASHTBL_SIZE)
 
 MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores");
 
@@ -101,6 +103,7 @@
  */
 struct ksem {
        LIST_ENTRY(ksem) ks_entry;      /* global list entry */
+       LIST_ENTRY(ksem) ks_hash;       /* hash list entry */
        struct simplelock ks_interlock; /* lock on this ksem */
        char *ks_name;                  /* if named, this is the name */
        unsigned int ks_ref;            /* number of references */
@@ -109,6 +112,7 @@
        gid_t ks_gid;                   /* creator gid */
        unsigned int ks_value;          /* current value */
        unsigned int ks_waiters;        /* number of waiters */
+       semid_t ks_id;                  /* unique identifier */
 };
 
 struct ksem_ref {
@@ -121,14 +125,24 @@
        LIST_HEAD(, ksem_ref) kp_ksems;
 };
 
+LIST_HEAD(ksem_list, ksem);
+
 /*
  * ksem_slock protects ksem_head and nsems.  Only named semaphores go
  * onto ksem_head.
  */
 static struct simplelock ksem_slock;
-static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
+static struct ksem_list ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
+static struct ksem_list ksem_hash[SEM_HASHTBL_SIZE];
 static int nsems = 0;
 
+/*
+ * ksem_counter is the last assigned semid_t.  It needs to be COMPAT_NETBSD32
+ * friendly, even though semid_t itself is defined as uintptr_t.
+ */
+static uint32_t ksem_counter = 1;
+
+
 static void
 ksem_free(struct ksem *ks)
 {
@@ -140,11 +154,13 @@
         */
        if (ks->ks_name == NULL) {
                simple_unlock(&ks->ks_interlock);
-               free(ks, M_SEM);
 
                simple_lock(&ksem_slock);
                nsems--;
+               LIST_REMOVE(ks, ks_hash);
                simple_unlock(&ksem_slock);
+
+               free(ks, M_SEM);
                return;
        }
        simple_unlock(&ks->ks_interlock);
@@ -239,6 +255,19 @@
 }
 
 static struct ksem *
+ksem_lookup_byid(semid_t id)
+{
+       struct ksem *ks;
+
+       LOCK_ASSERT(simple_lock_held(&ksem_slock));
+       LIST_FOREACH(ks, &ksem_hash[SEM_HASH(id)], ks_hash) {
+               if (ks->ks_id == id)
+                       return ks;
+       }
+       return NULL;
+}
+
+static struct ksem *
 ksem_lookup_byname(const char *name)
 {
        struct ksem *ks;
@@ -297,6 +326,14 @@
                return (ENFILE);
        }
        nsems++;
+       while (ksem_lookup_byid(ksem_counter) != NULL) {
+               ksem_counter++;
+               /* 0 is a special value for libpthread */
+               if (ksem_counter == 0)
+                       ksem_counter++;
+       }
+       ret->ks_id = ksem_counter;
+       LIST_INSERT_HEAD(&ksem_hash[SEM_HASH(ret->ks_id)], ret, ks_hash);
        simple_unlock(&ksem_slock);
 
        *ksret = ret;
@@ -310,16 +347,24 @@
                unsigned int value;
                semid_t *idp;
        } */ *uap = v;
+
+       return do_ksem_init(l, SCARG(uap, value), SCARG(uap, idp), copyout);
+}
+
+int
+do_ksem_init(struct lwp *l, unsigned int value, semid_t *idp,
+    copyout_t docopyout)
+{
        struct ksem *ks;
        semid_t id;
        int error;
 
        /* Note the mode does not matter for anonymous semaphores. */
-       error = ksem_create(l->l_proc, NULL, &ks, 0, SCARG(uap, value));
+       error = ksem_create(l->l_proc, NULL, &ks, 0, value);
        if (error)
                return (error);
        id = SEM_TO_ID(ks);
-       error = copyout(&id, SCARG(uap, idp), sizeof(id));
+       error = (*docopyout)(&id, idp, sizeof(id));
        if (error) {
                simple_lock(&ks->ks_interlock);
                ksem_delref(ks);
@@ -341,13 +386,22 @@
                unsigned int value;
                semid_t *idp;
        } */ *uap = v;
+
+       return do_ksem_open(l, SCARG(uap, name), SCARG(uap, oflag),
+           SCARG(uap, mode), SCARG(uap, value), SCARG(uap, idp), copyout);
+}
+
+int
+do_ksem_open(struct lwp *l, const char *semname, int oflag, mode_t mode,
+     unsigned int value, semid_t *idp, copyout_t docopyout)
+{
        char name[SEM_MAX_NAMELEN + 1];
        size_t done;
        int error;
        struct ksem *ksnew, *ks;
        semid_t id;
 
-       error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
+       error = copyinstr(semname, name, sizeof(name), &done);
        if (error)
                return (error);
 
@@ -358,7 +412,7 @@
        /* Found one? */
        if (ks != NULL) {
                /* Check for exclusive create. */
-               if (SCARG(uap, oflag) & O_EXCL) {
+               if (oflag & O_EXCL) {
                        simple_unlock(&ks->ks_interlock);
                        simple_unlock(&ksem_slock);
                        return (EEXIST);
@@ -378,7 +432,7 @@
                        return (error);
 
                id = SEM_TO_ID(ks);
-               error = copyout(&id, SCARG(uap, idp), sizeof(id));
+               error = (*docopyout)(&id, idp, sizeof(id));
                if (error) {
                        simple_lock(&ks->ks_interlock);
                        ksem_delref(ks);
@@ -393,7 +447,7 @@
        /*
         * didn't ask for creation? error.
         */
-       if ((SCARG(uap, oflag) & O_CREAT) == 0) {
+       if ((oflag & O_CREAT) == 0) {
                simple_unlock(&ksem_slock);
                return (ENOENT);
        }
@@ -402,13 +456,12 @@
         * We may block during creation, so drop the lock.
         */
        simple_unlock(&ksem_slock);
-       error = ksem_create(l->l_proc, name, &ksnew, SCARG(uap, mode),
-           SCARG(uap, value));
+       error = ksem_create(l->l_proc, name, &ksnew, mode, value);
        if (error != 0)
                return (error);
 
        id = SEM_TO_ID(ksnew);
-       error = copyout(&id, SCARG(uap, idp), sizeof(id));
+       error = (*docopyout)(&id, idp, sizeof(id));
        if (error) {
                free(ksnew->ks_name, M_SEM);
                ksnew->ks_name = NULL;
@@ -424,7 +477,7 @@
         */
        simple_lock(&ksem_slock);
        if ((ks = ksem_lookup_byname(name)) != NULL) {
-               if (SCARG(uap, oflag) & O_EXCL) {
+               if (oflag & O_EXCL) {
                        simple_unlock(&ks->ks_interlock);
                        simple_unlock(&ksem_slock);
 
@@ -453,7 +506,7 @@
        struct ksem_ref *ksr;
 
        LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
-               if (id == (semid_t) ksr->ksr_ksem) {
+               if (id == SEM_TO_ID(ksr->ksr_ksem)) {
                        simple_lock(&ksr->ksr_ksem->ks_interlock);
                        return (ksr->ksr_ksem);
                }
@@ -748,9 +801,13 @@
 void
 ksem_init(void)
 {
+       int i;
 
        simple_lock_init(&ksem_slock);
        exithook_establish(ksem_exithook, NULL);
        exechook_establish(ksem_exithook, NULL);
        forkhook_establish(ksem_forkhook);
+
+       for (i = 0; i < SEM_HASHTBL_SIZE; i++)
+               LIST_INIT(&ksem_hash[i]);
 }
diff -r 4d0918b0f4c5 -r 4b6ee64576e1 sys/sys/ksem.h
--- a/sys/sys/ksem.h    Sun Mar 05 00:32:43 2006 +0000
+++ b/sys/sys/ksem.h    Sun Mar 05 00:49:19 2006 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ksem.h,v 1.5 2005/12/11 12:25:20 christos Exp $        */
+/*     $NetBSD: ksem.h,v 1.6 2006/03/05 00:49:19 cube Exp $    */
 
 /*
  * Copyright (c) 2002 Alfred Perlstein <alfred%FreeBSD.org@localhost>
@@ -33,6 +33,10 @@
 
 #ifdef _KERNEL
 void ksem_init(void);
+
+int do_ksem_init(struct lwp *, unsigned int, semid_t *, copyout_t);
+int do_ksem_open(struct lwp *, const char *, int, mode_t, unsigned int,
+    semid_t *, copyout_t);
 #endif
 
 #ifdef _LIBC



Home | Main Index | Thread Index | Old Index