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