Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/kern Highly rewrite POSIX semaphore. Use file descripto...
details: https://anonhg.NetBSD.org/src/rev/05078e3e3127
branches: trunk
changeset: 764122:05078e3e3127
user: rmind <rmind%NetBSD.org@localhost>
date: Mon Apr 11 22:31:42 2011 +0000
description:
Highly rewrite POSIX semaphore. Use file descriptor subsystem, greatly
simplify reference counting, and fix various bugs which existed before,
e.g. some incorrect locking or sem_unlink() not checking for permissions.
diffstat:
sys/kern/uipc_sem.c | 1072 +++++++++++++++++++++-----------------------------
1 files changed, 442 insertions(+), 630 deletions(-)
diffs (truncated from 1273 to 300 lines):
diff -r e032d106fa16 -r 05078e3e3127 sys/kern/uipc_sem.c
--- a/sys/kern/uipc_sem.c Mon Apr 11 22:09:56 2011 +0000
+++ b/sys/kern/uipc_sem.c Mon Apr 11 22:31:42 2011 +0000
@@ -1,11 +1,11 @@
-/* $NetBSD: uipc_sem.c,v 1.29 2008/11/14 15:49:21 ad Exp $ */
+/* $NetBSD: uipc_sem.c,v 1.30 2011/04/11 22:31:43 rmind Exp $ */
/*-
- * Copyright (c) 2003, 2007, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2011 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, and by Andrew Doran.
+ * by Mindaugas Rasiukevicius.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -55,8 +55,12 @@
* SUCH DAMAGE.
*/
+/*
+ * Implementation of POSIX semaphore.
+ */
+
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.29 2008/11/14 15:49:21 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_sem.c,v 1.30 2011/04/11 22:31:43 rmind Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -67,6 +71,8 @@
#include <sys/stat.h>
#include <sys/kmem.h>
#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
#include <sys/kauth.h>
#include <sys/module.h>
#include <sys/mount.h>
@@ -74,14 +80,48 @@
#include <sys/syscallargs.h>
#include <sys/syscallvar.h>
-#define SEM_MAX_NAMELEN 14
-#define SEM_VALUE_MAX (~0U)
-#define SEM_HASHTBL_SIZE 13
+MODULE(MODULE_CLASS_MISC, ksem, NULL);
+
+#define SEM_MAX_NAMELEN 14
+#define SEM_VALUE_MAX (~0U)
+
+#define KS_UNLINKED 0x01
-#define SEM_TO_ID(x) (((x)->ks_id))
-#define SEM_HASH(id) ((id) % SEM_HASHTBL_SIZE)
+typedef struct ksem {
+ LIST_ENTRY(ksem) ks_entry; /* global list entry */
+ kmutex_t ks_lock; /* lock on this ksem */
+ kcondvar_t ks_cv; /* condition variable */
+ u_int ks_ref; /* number of references */
+ u_int ks_value; /* current value */
+ u_int ks_waiters; /* number of waiters */
+ char * ks_name; /* name, if named */
+ size_t ks_namelen; /* length of name */
+ int ks_flags; /* for KS_UNLINKED */
+ mode_t ks_mode; /* protection bits */
+ uid_t ks_uid; /* creator uid */
+ gid_t ks_gid; /* creator gid */
+} ksem_t;
-MODULE(MODULE_CLASS_MISC, ksem, NULL);
+static kmutex_t ksem_lock __cacheline_aligned;
+static LIST_HEAD(,ksem) ksem_head __cacheline_aligned;
+static u_int nsems __cacheline_aligned;
+
+static int ksem_sysinit(void);
+static int ksem_sysfini(bool);
+static int ksem_modcmd(modcmd_t, void *);
+static int ksem_close_fop(file_t *);
+
+static const struct fileops semops = {
+ .fo_read = fbadop_read,
+ .fo_write = fbadop_write,
+ .fo_ioctl = fbadop_ioctl,
+ .fo_fcntl = fnullop_fcntl,
+ .fo_poll = fnullop_poll,
+ .fo_stat = fbadop_stat,
+ .fo_close = ksem_close_fop,
+ .fo_kqfilter = fnullop_kqfilter,
+ .fo_restart = fnullop_restart,
+};
static const struct syscall_package ksem_syscalls[] = {
{ SYS__ksem_init, 0, (sy_call_t *)sys__ksem_init },
@@ -96,283 +136,186 @@
{ 0, 0, NULL },
};
-/*
- * Note: to read the ks_name member, you need either the ks_interlock
- * or the ksem_mutex. To write the ks_name member, you need both. Make
- * sure the order is ksem_mutex -> ks_interlock.
- */
-struct ksem {
- LIST_ENTRY(ksem) ks_entry; /* global list entry */
- LIST_ENTRY(ksem) ks_hash; /* hash list entry */
- kmutex_t ks_interlock; /* lock on this ksem */
- kcondvar_t ks_cv; /* condition variable */
- unsigned int ks_ref; /* number of references */
- char *ks_name; /* if named, this is the name */
- size_t ks_namelen; /* length of name */
- mode_t ks_mode; /* protection bits */
- uid_t ks_uid; /* creator uid */
- gid_t ks_gid; /* creator gid */
- unsigned int ks_value; /* current value */
- unsigned int ks_waiters; /* number of waiters */
- intptr_t ks_id; /* unique identifier */
-};
-
-struct ksem_ref {
- LIST_ENTRY(ksem_ref) ksr_list;
- struct ksem *ksr_ksem;
-};
-
-struct ksem_proc {
- krwlock_t kp_lock;
- LIST_HEAD(, ksem_ref) kp_ksems;
-};
-
-LIST_HEAD(ksem_list, ksem);
-
-/*
- * ksem_mutex protects ksem_head and nsems. Only named semaphores go
- * onto ksem_head.
- */
-static kmutex_t ksem_mutex;
-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 intptr_t. It needs to be COMPAT_NETBSD32
- * friendly, even though intptr_t itself is defined as uintptr_t.
- */
-static uint32_t ksem_counter = 1;
-
-static specificdata_key_t ksem_specificdata_key;
-static void *ksem_ehook;
-static void *ksem_fhook;
-
-static void
-ksem_free(struct ksem *ks)
+static int
+ksem_sysinit(void)
{
-
- KASSERT(mutex_owned(&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) {
- mutex_exit(&ks->ks_interlock);
- mutex_destroy(&ks->ks_interlock);
- cv_destroy(&ks->ks_cv);
-
- mutex_enter(&ksem_mutex);
- nsems--;
- LIST_REMOVE(ks, ks_hash);
- mutex_exit(&ksem_mutex);
-
- kmem_free(ks, sizeof(*ks));
- return;
- }
- mutex_exit(&ks->ks_interlock);
-}
-
-static inline void
-ksem_addref(struct ksem *ks)
-{
+ int error;
- KASSERT(mutex_owned(&ks->ks_interlock));
- ks->ks_ref++;
- KASSERT(ks->ks_ref != 0);
-}
-
-static inline void
-ksem_delref(struct ksem *ks)
-{
-
- KASSERT(mutex_owned(&ks->ks_interlock));
- KASSERT(ks->ks_ref != 0);
- if (--ks->ks_ref == 0) {
- ksem_free(ks);
- return;
- }
- mutex_exit(&ks->ks_interlock);
-}
+ nsems = 0;
+ mutex_init(&ksem_lock, MUTEX_DEFAULT, IPL_NONE);
+ LIST_INIT(&ksem_head);
-static struct ksem_proc *
-ksem_proc_alloc(void)
-{
- struct ksem_proc *kp;
-
- kp = kmem_alloc(sizeof(*kp), KM_SLEEP);
- rw_init(&kp->kp_lock);
- LIST_INIT(&kp->kp_ksems);
-
- return (kp);
-}
-
-static void
-ksem_proc_dtor(void *arg)
-{
- struct ksem_proc *kp = arg;
- struct ksem_ref *ksr;
-
- rw_enter(&kp->kp_lock, RW_WRITER);
-
- while ((ksr = LIST_FIRST(&kp->kp_ksems)) != NULL) {
- LIST_REMOVE(ksr, ksr_list);
- mutex_enter(&ksr->ksr_ksem->ks_interlock);
- ksem_delref(ksr->ksr_ksem);
- kmem_free(ksr, sizeof(*ksr));
+ error = syscall_establish(NULL, ksem_syscalls);
+ if (error) {
+ (void)ksem_sysfini(false);
}
-
- rw_exit(&kp->kp_lock);
- rw_destroy(&kp->kp_lock);
- kmem_free(kp, sizeof(*kp));
-}
-
-static void
-ksem_add_proc(struct proc *p, struct ksem *ks)
-{
- struct ksem_proc *kp;
- struct ksem_ref *ksr;
-
- kp = proc_getspecific(p, ksem_specificdata_key);
- if (kp == NULL) {
- kp = ksem_proc_alloc();
- proc_setspecific(p, ksem_specificdata_key, kp);
- }
-
- ksr = kmem_alloc(sizeof(*ksr), KM_SLEEP);
- ksr->ksr_ksem = ks;
-
- rw_enter(&kp->kp_lock, RW_WRITER);
- LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
- rw_exit(&kp->kp_lock);
-}
-
-/* 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;
-
- KASSERT(mutex_owned(&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);
+ return error;
}
static int
-ksem_perm(struct lwp *l, struct ksem *ks)
+ksem_sysfini(bool interface)
{
- kauth_cred_t uc;
+ int error;
- KASSERT(mutex_owned(&ks->ks_interlock));
- uc = l->l_cred;
- if ((kauth_cred_geteuid(uc) == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
- (kauth_cred_getegid(uc) == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
- (ks->ks_mode & S_IWOTH) != 0 ||
- kauth_authorize_generic(uc, KAUTH_GENERIC_ISSUSER, NULL) == 0)
- return (0);
- return (EPERM);
+ if (interface) {
+ error = syscall_disestablish(NULL, ksem_syscalls);
+ if (error != 0) {
Home |
Main Index |
Thread Index |
Old Index