Source-Changes-HG archive

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

[src/trunk]: src/sys/kern Major overhaul of this code, fixing locking protoco...



details:   https://anonhg.NetBSD.org/src/rev/2c66a94c44b4
branches:  trunk
changeset: 542230:2c66a94c44b4
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Fri Jan 24 01:46:27 2003 +0000

description:
Major overhaul of this code, fixing locking protocol issues and handling
of semaphores at fork time.

diffstat:

 sys/kern/uipc_sem.c |  810 +++++++++++++++++++++++++++++----------------------
 1 files changed, 453 insertions(+), 357 deletions(-)

diffs (truncated from 1016 to 300 lines):

diff -r 133c2f714dbd -r 2c66a94c44b4 sys/kern/uipc_sem.c
--- a/sys/kern/uipc_sem.c       Fri Jan 24 01:42:52 2003 +0000
+++ b/sys/kern/uipc_sem.c       Fri Jan 24 01:46:27 2003 +0000
@@ -1,4 +1,40 @@
-/* $NetBSD: uipc_sem.c,v 1.2 2003/01/20 20:24:22 christos Exp $ */
+/*     $NetBSD: uipc_sem.c,v 1.3 2003/01/24 01:46:27 thorpej Exp $     */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
 
 /*
  * Copyright (c) 2002 Alfred Perlstein <alfred%FreeBSD.org@localhost>
@@ -24,8 +60,6 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- *     $FreeBSD: src/sys/kern/uipc_sem.c,v 1.4 2003/01/10 23:13:16 alfred Exp $
  */
 
 #include "opt_posix.h"
@@ -53,125 +87,174 @@
 #define SEM_VALUE_MAX (~0U)
 
 #define SEM_TO_ID(x)   ((intptr_t)(x))
-#define ID_TO_SEM(x)   ksem_id_to_sem(x)
 
-struct kuser {
-       pid_t ku_pid;
-       LIST_ENTRY(kuser) ku_next;
-};
-
-/* For sysctl eventually */
-int nsems = 0;
-
+/*
+ * Note: to read the ks_name member, you need either the ks_interlock
+ * or the ksem_slock.  To write the ks_name member, you need both.  Make
+ * sure the order is ksem_slock -> ks_interlock.
+ */
 struct ksem {
        LIST_ENTRY(ksem) ks_entry;      /* global list entry */
-       int ks_onlist;                  /* boolean if on a list (ks_entry) */
+       struct simplelock ks_interlock; /* lock on this ksem */
        char *ks_name;                  /* if named, this is the name */
-       int ks_ref;                     /* number of references */
+       unsigned int ks_ref;            /* number of references */
        mode_t ks_mode;                 /* protection bits */
        uid_t ks_uid;                   /* creator uid */
        gid_t ks_gid;                   /* creator gid */
        unsigned int ks_value;          /* current value */
-       int ks_waiters;                 /* number of waiters */
-       LIST_HEAD(, kuser) ks_users;    /* pids using this sem */
+       unsigned int ks_waiters;        /* number of waiters */
+};
+
+struct ksem_ref {
+       LIST_ENTRY(ksem_ref) ksr_list;
+       struct ksem *ksr_ksem;
+};
+
+struct ksem_proc {
+       struct lock kp_lock;
+       LIST_HEAD(, ksem_ref) kp_ksems;
 };
 
 /*
- * available semaphores go here, this includes sys__ksem_init and any semaphores
- * created via sys__ksem_open that have not yet been unlinked.
- */
-LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
-/*
- * semaphores still in use but have been ksem_unlink()'d go here.
+ * ksem_slock protects ksem_head and nsems.  Only named semaphores go
+ * onto ksem_head.
  */
-LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
-
 static struct simplelock ksem_slock;
+static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
+static int nsems = 0;
 
-#ifdef SEM_DEBUG
-#define DP(x)  printf x
-#else
-#define DP(x)
-#endif
+static void
+ksem_free(struct ksem *ks)
+{
 
-static __inline void ksem_ref(struct ksem *ks);
-static __inline void ksem_rel(struct ksem *ks);
-static __inline struct ksem *ksem_id_to_sem(semid_t id);
-static __inline struct kuser *ksem_getuser(struct proc *p, struct ksem *ks);
+       LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
+       /*
+        * If the ksem is anonymous (or has been unlinked), then
+        * this is the end if its life.
+        */
+       if (ks->ks_name == NULL) {
+               simple_unlock(&ks->ks_interlock);
+               free(ks, M_SEM);
 
-static struct ksem *ksem_lookup_byname(const char *name);
-static int ksem_create(struct lwp *l, const char *name,
-    struct ksem **ksret, mode_t mode, unsigned int value);
-static void ksem_free(struct ksem *ksnew);
-static int ksem_perm(struct proc *p, struct ksem *ks);
-static void ksem_enter(struct proc *p, struct ksem *ks);
-static int ksem_leave(struct proc *p, struct ksem *ks);
-static void ksem_exithook(struct proc *p, void *arg);
-static int ksem_hasopen(struct proc *p, struct ksem *ks);
-static int ksem_wait(struct lwp *l, semid_t id, int tryflag);
-
+               simple_lock(&ksem_slock);
+               nsems--;
+               simple_unlock(&ksem_slock);
+               return;
+       }
+       simple_unlock(&ks->ks_interlock);
+}
 
 static __inline void
-ksem_ref(struct ksem *ks)
+ksem_addref(struct ksem *ks)
 {
 
+       LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
        ks->ks_ref++;
-       DP(("ksem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
+       KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
 }
 
 static __inline void
-ksem_rel(struct ksem *ks)
+ksem_delref(struct ksem *ks)
 {
 
-       DP(("ksem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
-       if (--ks->ks_ref == 0)
+       LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
+       KASSERT(ks->ks_ref != 0);       /* XXX KDASSERT */
+       if (--ks->ks_ref == 0) {
                ksem_free(ks);
+               return;
+       }
+       simple_unlock(&ks->ks_interlock);
+}
+
+static struct ksem_proc *
+ksem_proc_alloc(void)
+{
+       struct ksem_proc *kp;
+
+       kp = malloc(sizeof(*kp), M_SEM, M_WAITOK);
+       lockinit(&kp->kp_lock, PWAIT, "ksproc", 0, 0);
+       LIST_INIT(&kp->kp_ksems);
+
+       return (kp);
 }
 
-static __inline struct ksem *
-ksem_id_to_sem(id)
-       semid_t id;
+static void
+ksem_add_proc(struct proc *p, struct ksem *ks)
+{
+       struct ksem_proc *kp;
+       struct ksem_ref *ksr;
+
+       if (p->p_ksems == NULL) {
+               kp = ksem_proc_alloc();
+               p->p_ksems = kp;
+       } else
+               kp = p->p_ksems;
+
+       ksr = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
+       ksr->ksr_ksem = ks;
+
+       lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
+       LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
+       lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
+}
+
+/* We MUST have a write lock on the ksem_proc list! */
+static struct ksem_ref *
+ksem_drop_proc(struct ksem_proc *kp, struct ksem *ks)
+{
+       struct ksem_ref *ksr;
+
+       LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
+       LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
+               if (ksr->ksr_ksem == ks) {
+                       ksem_delref(ks);
+                       LIST_REMOVE(ksr, ksr_list);
+                       return (ksr);
+               }
+       }
+#ifdef DIAGNOSTIC
+       panic("ksem_drop_proc: ksem_proc %p ksem %p", kp, ks);
+#endif
+       return (NULL);
+}
+
+static int
+ksem_perm(struct proc *p, struct ksem *ks)
+{
+       struct ucred *uc;
+
+       LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
+       uc = p->p_ucred;
+       if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
+           (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
+           (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
+               return (0);
+       return (EPERM);
+}
+
+static struct ksem *
+ksem_lookup_byname(const char *name)
 {
        struct ksem *ks;
 
-       DP(("id_to_sem: id = 0x%ld\n", id));
+       LOCK_ASSERT(simple_lock_held(&ksem_slock));
        LIST_FOREACH(ks, &ksem_head, ks_entry) {
-               DP(("id_to_sem: ks = %p\n", ks));
-               if (ks == (struct ksem *)id)
+               if (strcmp(ks->ks_name, name) == 0) {
+                       simple_lock(&ks->ks_interlock);
                        return (ks);
+               }
        }
        return (NULL);
 }
 
-static struct ksem *
-ksem_lookup_byname(name)
-       const char *name;
-{
-       struct ksem *ks;
-
-       LIST_FOREACH(ks, &ksem_head, ks_entry)
-               if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
-                       return (ks);
-       return (NULL);
-}
-
 static int
-ksem_create(l, name, ksret, mode, value)
-       struct lwp *l;
-       const char *name;
-       struct ksem **ksret;
-       mode_t mode;
-       unsigned int value;
+ksem_create(struct proc *p, const char *name, struct ksem **ksret,
+    mode_t mode, unsigned int value)
 {
        struct ksem *ret;
-       struct proc *p;
        struct ucred *uc;
        size_t len;
-       int error;
 
-       DP(("ksem_create %s %p %d %u\n", name ? name : "(null)", ksret, mode,
-           value));



Home | Main Index | Thread Index | Old Index