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