Home | History | Annotate | Line # | Download | only in kern
uipc_sem.c revision 1.5
      1  1.5      matt /*	$NetBSD: uipc_sem.c,v 1.5 2003/04/23 17:50:51 matt Exp $	*/
      2  1.3   thorpej 
      3  1.3   thorpej /*-
      4  1.3   thorpej  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      5  1.3   thorpej  * All rights reserved.
      6  1.3   thorpej  *
      7  1.3   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8  1.3   thorpej  * by Jason R. Thorpe of Wasabi Systems, Inc.
      9  1.3   thorpej  *
     10  1.3   thorpej  * Redistribution and use in source and binary forms, with or without
     11  1.3   thorpej  * modification, are permitted provided that the following conditions
     12  1.3   thorpej  * are met:
     13  1.3   thorpej  * 1. Redistributions of source code must retain the above copyright
     14  1.3   thorpej  *    notice, this list of conditions and the following disclaimer.
     15  1.3   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.3   thorpej  *    notice, this list of conditions and the following disclaimer in the
     17  1.3   thorpej  *    documentation and/or other materials provided with the distribution.
     18  1.3   thorpej  * 3. All advertising materials mentioning features or use of this software
     19  1.3   thorpej  *    must display the following acknowledgement:
     20  1.3   thorpej  *        This product includes software developed by the NetBSD
     21  1.3   thorpej  *        Foundation, Inc. and its contributors.
     22  1.3   thorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.3   thorpej  *    contributors may be used to endorse or promote products derived
     24  1.3   thorpej  *    from this software without specific prior written permission.
     25  1.3   thorpej  *
     26  1.3   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.3   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.3   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.3   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.3   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.3   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.3   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.3   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.3   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.3   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.3   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     37  1.3   thorpej  */
     38  1.1  christos 
     39  1.1  christos /*
     40  1.1  christos  * Copyright (c) 2002 Alfred Perlstein <alfred (at) FreeBSD.org>
     41  1.1  christos  * All rights reserved.
     42  1.1  christos  *
     43  1.1  christos  * Redistribution and use in source and binary forms, with or without
     44  1.1  christos  * modification, are permitted provided that the following conditions
     45  1.1  christos  * are met:
     46  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     47  1.1  christos  *    notice, this list of conditions and the following disclaimer.
     48  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     49  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     50  1.1  christos  *    documentation and/or other materials provided with the distribution.
     51  1.1  christos  *
     52  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     53  1.1  christos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     54  1.1  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     55  1.1  christos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     56  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     57  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     58  1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     59  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     60  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     61  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     62  1.1  christos  * SUCH DAMAGE.
     63  1.1  christos  */
     64  1.1  christos 
     65  1.1  christos #include "opt_posix.h"
     66  1.1  christos 
     67  1.1  christos #include <sys/param.h>
     68  1.1  christos #include <sys/systm.h>
     69  1.1  christos #include <sys/kernel.h>
     70  1.1  christos #include <sys/proc.h>
     71  1.1  christos #include <sys/lock.h>
     72  1.1  christos #include <sys/ksem.h>
     73  1.5      matt #include <sys/sa.h>
     74  1.1  christos #include <sys/syscall.h>
     75  1.1  christos #include <sys/stat.h>
     76  1.1  christos #include <sys/malloc.h>
     77  1.1  christos #include <sys/fcntl.h>
     78  1.1  christos 
     79  1.1  christos #include <sys/mount.h>
     80  1.1  christos 
     81  1.1  christos #include <sys/syscallargs.h>
     82  1.1  christos 
     83  1.1  christos #ifndef SEM_MAX
     84  1.1  christos #define SEM_MAX	30
     85  1.1  christos #endif
     86  1.1  christos 
     87  1.1  christos #define SEM_MAX_NAMELEN	14
     88  1.1  christos #define SEM_VALUE_MAX (~0U)
     89  1.1  christos 
     90  1.1  christos #define SEM_TO_ID(x)	((intptr_t)(x))
     91  1.4   thorpej 
     92  1.4   thorpej MALLOC_DEFINE(M_SEM, "p1003_1b_sem", "p1003_1b semaphores");
     93  1.1  christos 
     94  1.3   thorpej /*
     95  1.3   thorpej  * Note: to read the ks_name member, you need either the ks_interlock
     96  1.3   thorpej  * or the ksem_slock.  To write the ks_name member, you need both.  Make
     97  1.3   thorpej  * sure the order is ksem_slock -> ks_interlock.
     98  1.3   thorpej  */
     99  1.1  christos struct ksem {
    100  1.1  christos 	LIST_ENTRY(ksem) ks_entry;	/* global list entry */
    101  1.3   thorpej 	struct simplelock ks_interlock;	/* lock on this ksem */
    102  1.1  christos 	char *ks_name;			/* if named, this is the name */
    103  1.3   thorpej 	unsigned int ks_ref;		/* number of references */
    104  1.1  christos 	mode_t ks_mode;			/* protection bits */
    105  1.1  christos 	uid_t ks_uid;			/* creator uid */
    106  1.1  christos 	gid_t ks_gid;			/* creator gid */
    107  1.1  christos 	unsigned int ks_value;		/* current value */
    108  1.3   thorpej 	unsigned int ks_waiters;	/* number of waiters */
    109  1.3   thorpej };
    110  1.3   thorpej 
    111  1.3   thorpej struct ksem_ref {
    112  1.3   thorpej 	LIST_ENTRY(ksem_ref) ksr_list;
    113  1.3   thorpej 	struct ksem *ksr_ksem;
    114  1.3   thorpej };
    115  1.3   thorpej 
    116  1.3   thorpej struct ksem_proc {
    117  1.3   thorpej 	struct lock kp_lock;
    118  1.3   thorpej 	LIST_HEAD(, ksem_ref) kp_ksems;
    119  1.1  christos };
    120  1.1  christos 
    121  1.1  christos /*
    122  1.3   thorpej  * ksem_slock protects ksem_head and nsems.  Only named semaphores go
    123  1.3   thorpej  * onto ksem_head.
    124  1.1  christos  */
    125  1.1  christos static struct simplelock ksem_slock;
    126  1.3   thorpej static LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
    127  1.3   thorpej static int nsems = 0;
    128  1.1  christos 
    129  1.3   thorpej static void
    130  1.3   thorpej ksem_free(struct ksem *ks)
    131  1.3   thorpej {
    132  1.1  christos 
    133  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    134  1.3   thorpej 	/*
    135  1.3   thorpej 	 * If the ksem is anonymous (or has been unlinked), then
    136  1.3   thorpej 	 * this is the end if its life.
    137  1.3   thorpej 	 */
    138  1.3   thorpej 	if (ks->ks_name == NULL) {
    139  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    140  1.3   thorpej 		free(ks, M_SEM);
    141  1.1  christos 
    142  1.3   thorpej 		simple_lock(&ksem_slock);
    143  1.3   thorpej 		nsems--;
    144  1.3   thorpej 		simple_unlock(&ksem_slock);
    145  1.3   thorpej 		return;
    146  1.3   thorpej 	}
    147  1.3   thorpej 	simple_unlock(&ks->ks_interlock);
    148  1.3   thorpej }
    149  1.1  christos 
    150  1.1  christos static __inline void
    151  1.3   thorpej ksem_addref(struct ksem *ks)
    152  1.1  christos {
    153  1.1  christos 
    154  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    155  1.1  christos 	ks->ks_ref++;
    156  1.3   thorpej 	KASSERT(ks->ks_ref != 0);	/* XXX KDASSERT */
    157  1.1  christos }
    158  1.1  christos 
    159  1.1  christos static __inline void
    160  1.3   thorpej ksem_delref(struct ksem *ks)
    161  1.1  christos {
    162  1.1  christos 
    163  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    164  1.3   thorpej 	KASSERT(ks->ks_ref != 0);	/* XXX KDASSERT */
    165  1.3   thorpej 	if (--ks->ks_ref == 0) {
    166  1.1  christos 		ksem_free(ks);
    167  1.3   thorpej 		return;
    168  1.3   thorpej 	}
    169  1.3   thorpej 	simple_unlock(&ks->ks_interlock);
    170  1.3   thorpej }
    171  1.3   thorpej 
    172  1.3   thorpej static struct ksem_proc *
    173  1.3   thorpej ksem_proc_alloc(void)
    174  1.3   thorpej {
    175  1.3   thorpej 	struct ksem_proc *kp;
    176  1.3   thorpej 
    177  1.3   thorpej 	kp = malloc(sizeof(*kp), M_SEM, M_WAITOK);
    178  1.3   thorpej 	lockinit(&kp->kp_lock, PWAIT, "ksproc", 0, 0);
    179  1.3   thorpej 	LIST_INIT(&kp->kp_ksems);
    180  1.3   thorpej 
    181  1.3   thorpej 	return (kp);
    182  1.1  christos }
    183  1.1  christos 
    184  1.3   thorpej static void
    185  1.3   thorpej ksem_add_proc(struct proc *p, struct ksem *ks)
    186  1.3   thorpej {
    187  1.3   thorpej 	struct ksem_proc *kp;
    188  1.3   thorpej 	struct ksem_ref *ksr;
    189  1.3   thorpej 
    190  1.3   thorpej 	if (p->p_ksems == NULL) {
    191  1.3   thorpej 		kp = ksem_proc_alloc();
    192  1.3   thorpej 		p->p_ksems = kp;
    193  1.3   thorpej 	} else
    194  1.3   thorpej 		kp = p->p_ksems;
    195  1.3   thorpej 
    196  1.3   thorpej 	ksr = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
    197  1.3   thorpej 	ksr->ksr_ksem = ks;
    198  1.3   thorpej 
    199  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
    200  1.3   thorpej 	LIST_INSERT_HEAD(&kp->kp_ksems, ksr, ksr_list);
    201  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    202  1.3   thorpej }
    203  1.3   thorpej 
    204  1.3   thorpej /* We MUST have a write lock on the ksem_proc list! */
    205  1.3   thorpej static struct ksem_ref *
    206  1.3   thorpej ksem_drop_proc(struct ksem_proc *kp, struct ksem *ks)
    207  1.1  christos {
    208  1.3   thorpej 	struct ksem_ref *ksr;
    209  1.1  christos 
    210  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    211  1.3   thorpej 	LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
    212  1.3   thorpej 		if (ksr->ksr_ksem == ks) {
    213  1.3   thorpej 			ksem_delref(ks);
    214  1.3   thorpej 			LIST_REMOVE(ksr, ksr_list);
    215  1.3   thorpej 			return (ksr);
    216  1.3   thorpej 		}
    217  1.1  christos 	}
    218  1.3   thorpej #ifdef DIAGNOSTIC
    219  1.3   thorpej 	panic("ksem_drop_proc: ksem_proc %p ksem %p", kp, ks);
    220  1.3   thorpej #endif
    221  1.1  christos 	return (NULL);
    222  1.1  christos }
    223  1.1  christos 
    224  1.3   thorpej static int
    225  1.3   thorpej ksem_perm(struct proc *p, struct ksem *ks)
    226  1.3   thorpej {
    227  1.3   thorpej 	struct ucred *uc;
    228  1.3   thorpej 
    229  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    230  1.3   thorpej 	uc = p->p_ucred;
    231  1.3   thorpej 	if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
    232  1.3   thorpej 	    (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
    233  1.3   thorpej 	    (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
    234  1.3   thorpej 		return (0);
    235  1.3   thorpej 	return (EPERM);
    236  1.3   thorpej }
    237  1.3   thorpej 
    238  1.1  christos static struct ksem *
    239  1.3   thorpej ksem_lookup_byname(const char *name)
    240  1.1  christos {
    241  1.1  christos 	struct ksem *ks;
    242  1.1  christos 
    243  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ksem_slock));
    244  1.3   thorpej 	LIST_FOREACH(ks, &ksem_head, ks_entry) {
    245  1.3   thorpej 		if (strcmp(ks->ks_name, name) == 0) {
    246  1.3   thorpej 			simple_lock(&ks->ks_interlock);
    247  1.1  christos 			return (ks);
    248  1.3   thorpej 		}
    249  1.3   thorpej 	}
    250  1.1  christos 	return (NULL);
    251  1.1  christos }
    252  1.1  christos 
    253  1.1  christos static int
    254  1.3   thorpej ksem_create(struct proc *p, const char *name, struct ksem **ksret,
    255  1.3   thorpej     mode_t mode, unsigned int value)
    256  1.1  christos {
    257  1.1  christos 	struct ksem *ret;
    258  1.1  christos 	struct ucred *uc;
    259  1.1  christos 	size_t len;
    260  1.1  christos 
    261  1.1  christos 	uc = p->p_ucred;
    262  1.1  christos 	if (value > SEM_VALUE_MAX)
    263  1.1  christos 		return (EINVAL);
    264  1.1  christos 	ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
    265  1.1  christos 	if (name != NULL) {
    266  1.1  christos 		len = strlen(name);
    267  1.1  christos 		if (len > SEM_MAX_NAMELEN) {
    268  1.1  christos 			free(ret, M_SEM);
    269  1.1  christos 			return (ENAMETOOLONG);
    270  1.1  christos 		}
    271  1.1  christos 		/* name must start with a '/' but not contain one. */
    272  1.1  christos 		if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
    273  1.1  christos 			free(ret, M_SEM);
    274  1.1  christos 			return (EINVAL);
    275  1.1  christos 		}
    276  1.1  christos 		ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
    277  1.1  christos 		strcpy(ret->ks_name, name);
    278  1.3   thorpej 	} else
    279  1.1  christos 		ret->ks_name = NULL;
    280  1.1  christos 	ret->ks_mode = mode;
    281  1.1  christos 	ret->ks_value = value;
    282  1.1  christos 	ret->ks_ref = 1;
    283  1.1  christos 	ret->ks_waiters = 0;
    284  1.1  christos 	ret->ks_uid = uc->cr_uid;
    285  1.1  christos 	ret->ks_gid = uc->cr_gid;
    286  1.3   thorpej 	simple_lock_init(&ret->ks_interlock);
    287  1.3   thorpej 
    288  1.1  christos 	simple_lock(&ksem_slock);
    289  1.1  christos 	if (nsems >= SEM_MAX) {
    290  1.3   thorpej 		simple_unlock(&ksem_slock);
    291  1.3   thorpej 		if (ret->ks_name != NULL)
    292  1.3   thorpej 			free(ret->ks_name, M_SEM);
    293  1.3   thorpej 		free(ret, M_SEM);
    294  1.3   thorpej 		return (ENFILE);
    295  1.1  christos 	}
    296  1.3   thorpej 	nsems++;
    297  1.1  christos 	simple_unlock(&ksem_slock);
    298  1.3   thorpej 
    299  1.3   thorpej 	*ksret = ret;
    300  1.3   thorpej 	return (0);
    301  1.1  christos }
    302  1.1  christos 
    303  1.1  christos int
    304  1.2  christos sys__ksem_init(struct lwp *l, void *v, register_t *retval)
    305  1.1  christos {
    306  1.2  christos 	struct sys__ksem_init_args /* {
    307  1.1  christos 		unsigned int value;
    308  1.1  christos 		semid_t *idp;
    309  1.1  christos 	} */ *uap = v;
    310  1.1  christos 	struct ksem *ks;
    311  1.1  christos 	semid_t id;
    312  1.1  christos 	int error;
    313  1.1  christos 
    314  1.3   thorpej 	/* Note the mode does not matter for anonymous semaphores. */
    315  1.3   thorpej 	error = ksem_create(l->l_proc, NULL, &ks, 0, SCARG(uap, value));
    316  1.1  christos 	if (error)
    317  1.1  christos 		return (error);
    318  1.1  christos 	id = SEM_TO_ID(ks);
    319  1.1  christos 	error = copyout(&id, SCARG(uap, idp), sizeof(id));
    320  1.1  christos 	if (error) {
    321  1.3   thorpej 		simple_lock(&ks->ks_interlock);
    322  1.3   thorpej 		ksem_delref(ks);
    323  1.1  christos 		return (error);
    324  1.1  christos 	}
    325  1.3   thorpej 
    326  1.3   thorpej 	ksem_add_proc(l->l_proc, ks);
    327  1.3   thorpej 
    328  1.3   thorpej 	return (0);
    329  1.1  christos }
    330  1.1  christos 
    331  1.1  christos int
    332  1.2  christos sys__ksem_open(struct lwp *l, void *v, register_t *retval)
    333  1.1  christos {
    334  1.2  christos 	struct sys__ksem_open_args /* {
    335  1.1  christos 		const char *name;
    336  1.1  christos 		int oflag;
    337  1.1  christos 		mode_t mode;
    338  1.1  christos 		unsigned int value;
    339  1.1  christos 		semid_t *idp;
    340  1.1  christos 	} */ *uap = v;
    341  1.1  christos 	char name[SEM_MAX_NAMELEN + 1];
    342  1.1  christos 	size_t done;
    343  1.1  christos 	int error;
    344  1.1  christos 	struct ksem *ksnew, *ks;
    345  1.1  christos 	semid_t id;
    346  1.1  christos 
    347  1.1  christos 	error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
    348  1.1  christos 	if (error)
    349  1.1  christos 		return (error);
    350  1.1  christos 
    351  1.1  christos 	ksnew = NULL;
    352  1.1  christos 	simple_lock(&ksem_slock);
    353  1.1  christos 	ks = ksem_lookup_byname(name);
    354  1.3   thorpej 
    355  1.3   thorpej 	/* Found one? */
    356  1.3   thorpej 	if (ks != NULL) {
    357  1.3   thorpej 		/* Check for exclusive create. */
    358  1.3   thorpej 		if (SCARG(uap, oflag) & O_EXCL) {
    359  1.3   thorpej 			simple_unlock(&ks->ks_interlock);
    360  1.1  christos 			simple_unlock(&ksem_slock);
    361  1.3   thorpej 			return (EEXIST);
    362  1.1  christos 		}
    363  1.3   thorpej  found_one:
    364  1.1  christos 		/*
    365  1.3   thorpej 		 * Verify permissions.  If we can access it, add
    366  1.3   thorpej 		 * this process's reference.
    367  1.1  christos 		 */
    368  1.3   thorpej 		LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    369  1.1  christos 		error = ksem_perm(l->l_proc, ks);
    370  1.3   thorpej 		if (error == 0)
    371  1.3   thorpej 			ksem_addref(ks);
    372  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    373  1.1  christos 		simple_unlock(&ksem_slock);
    374  1.1  christos 		if (error)
    375  1.1  christos 			return (error);
    376  1.3   thorpej 
    377  1.1  christos 		id = SEM_TO_ID(ks);
    378  1.1  christos 		error = copyout(&id, SCARG(uap, idp), sizeof(id));
    379  1.1  christos 		if (error) {
    380  1.3   thorpej 			simple_lock(&ks->ks_interlock);
    381  1.3   thorpej 			ksem_delref(ks);
    382  1.1  christos 			return (error);
    383  1.1  christos 		}
    384  1.3   thorpej 
    385  1.3   thorpej 		ksem_add_proc(l->l_proc, ks);
    386  1.3   thorpej 
    387  1.3   thorpej 		return (0);
    388  1.3   thorpej 	}
    389  1.3   thorpej 
    390  1.3   thorpej 	/*
    391  1.3   thorpej 	 * didn't ask for creation? error.
    392  1.3   thorpej 	 */
    393  1.3   thorpej 	if ((SCARG(uap, oflag) & O_CREAT) == 0) {
    394  1.1  christos 		simple_unlock(&ksem_slock);
    395  1.3   thorpej 		return (ENOENT);
    396  1.1  christos 	}
    397  1.1  christos 
    398  1.3   thorpej 	/*
    399  1.3   thorpej 	 * We may block during creation, so drop the lock.
    400  1.3   thorpej 	 */
    401  1.3   thorpej 	simple_unlock(&ksem_slock);
    402  1.3   thorpej 	error = ksem_create(l->l_proc, name, &ksnew, SCARG(uap, mode),
    403  1.3   thorpej 	    SCARG(uap, value));
    404  1.3   thorpej 	if (error != 0)
    405  1.3   thorpej 		return (error);
    406  1.3   thorpej 
    407  1.3   thorpej 	id = SEM_TO_ID(ksnew);
    408  1.3   thorpej 	error = copyout(&id, SCARG(uap, idp), sizeof(id));
    409  1.3   thorpej 	if (error) {
    410  1.3   thorpej 		free(ksnew->ks_name, M_SEM);
    411  1.3   thorpej 		ksnew->ks_name = NULL;
    412  1.1  christos 
    413  1.3   thorpej 		simple_lock(&ksnew->ks_interlock);
    414  1.3   thorpej 		ksem_delref(ksnew);
    415  1.3   thorpej 		return (error);
    416  1.3   thorpej 	}
    417  1.1  christos 
    418  1.3   thorpej 	/*
    419  1.3   thorpej 	 * We need to make sure we haven't lost a race while
    420  1.3   thorpej 	 * allocating during creation.
    421  1.3   thorpej 	 */
    422  1.3   thorpej 	simple_lock(&ksem_slock);
    423  1.3   thorpej 	if ((ks = ksem_lookup_byname(name)) != NULL) {
    424  1.3   thorpej 		if (SCARG(uap, oflag) & O_EXCL) {
    425  1.3   thorpej 			simple_unlock(&ks->ks_interlock);
    426  1.3   thorpej 			simple_unlock(&ksem_slock);
    427  1.1  christos 
    428  1.3   thorpej 			free(ksnew->ks_name, M_SEM);
    429  1.3   thorpej 			ksnew->ks_name = NULL;
    430  1.1  christos 
    431  1.3   thorpej 			simple_lock(&ksnew->ks_interlock);
    432  1.3   thorpej 			ksem_delref(ksnew);
    433  1.3   thorpej 			return (EEXIST);
    434  1.3   thorpej 		}
    435  1.3   thorpej 		goto found_one;
    436  1.3   thorpej 	} else {
    437  1.3   thorpej 		/* ksnew already has its initial reference. */
    438  1.3   thorpej 		LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
    439  1.3   thorpej 		simple_unlock(&ksem_slock);
    440  1.1  christos 
    441  1.3   thorpej 		ksem_add_proc(l->l_proc, ksnew);
    442  1.1  christos 	}
    443  1.3   thorpej 	return (error);
    444  1.1  christos }
    445  1.1  christos 
    446  1.3   thorpej /* We must have a read lock on the ksem_proc list! */
    447  1.3   thorpej static struct ksem *
    448  1.3   thorpej ksem_lookup_proc(struct ksem_proc *kp, semid_t id)
    449  1.1  christos {
    450  1.3   thorpej 	struct ksem_ref *ksr;
    451  1.1  christos 
    452  1.3   thorpej 	LIST_FOREACH(ksr, &kp->kp_ksems, ksr_list) {
    453  1.3   thorpej 		if (id == (semid_t) ksr->ksr_ksem) {
    454  1.3   thorpej 			simple_lock(&ksr->ksr_ksem->ks_interlock);
    455  1.3   thorpej 			return (ksr->ksr_ksem);
    456  1.3   thorpej 		}
    457  1.1  christos 	}
    458  1.3   thorpej 
    459  1.3   thorpej 	return (NULL);
    460  1.1  christos }
    461  1.1  christos 
    462  1.1  christos int
    463  1.2  christos sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
    464  1.1  christos {
    465  1.2  christos 	struct sys__ksem_unlink_args /* {
    466  1.1  christos 		const char *name;
    467  1.1  christos 	} */ *uap = v;
    468  1.3   thorpej 	char name[SEM_MAX_NAMELEN + 1], *cp;
    469  1.1  christos 	size_t done;
    470  1.1  christos 	struct ksem *ks;
    471  1.1  christos 	int error;
    472  1.1  christos 
    473  1.1  christos 	error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
    474  1.1  christos 	if (error)
    475  1.1  christos 		return error;
    476  1.1  christos 
    477  1.1  christos 	simple_lock(&ksem_slock);
    478  1.1  christos 	ks = ksem_lookup_byname(name);
    479  1.3   thorpej 	if (ks == NULL) {
    480  1.3   thorpej 		simple_unlock(&ksem_slock);
    481  1.3   thorpej 		return (ENOENT);
    482  1.1  christos 	}
    483  1.3   thorpej 
    484  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    485  1.3   thorpej 
    486  1.3   thorpej 	LIST_REMOVE(ks, ks_entry);
    487  1.3   thorpej 	cp = ks->ks_name;
    488  1.3   thorpej 	ks->ks_name = NULL;
    489  1.3   thorpej 
    490  1.1  christos 	simple_unlock(&ksem_slock);
    491  1.3   thorpej 
    492  1.3   thorpej 	if (ks->ks_ref == 0)
    493  1.3   thorpej 		ksem_free(ks);
    494  1.3   thorpej 	else
    495  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    496  1.3   thorpej 
    497  1.3   thorpej 	free(cp, M_SEM);
    498  1.3   thorpej 
    499  1.3   thorpej 	return (0);
    500  1.1  christos }
    501  1.1  christos 
    502  1.1  christos int
    503  1.2  christos sys__ksem_close(struct lwp *l, void *v, register_t *retval)
    504  1.1  christos {
    505  1.2  christos 	struct sys__ksem_close_args /* {
    506  1.1  christos 		semid_t id;
    507  1.1  christos 	} */ *uap = v;
    508  1.3   thorpej 	struct ksem_proc *kp;
    509  1.3   thorpej 	struct ksem_ref *ksr;
    510  1.1  christos 	struct ksem *ks;
    511  1.1  christos 
    512  1.3   thorpej 	if ((kp = l->l_proc->p_ksems) == NULL)
    513  1.3   thorpej 		return (EINVAL);
    514  1.3   thorpej 
    515  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
    516  1.3   thorpej 
    517  1.3   thorpej 	ks = ksem_lookup_proc(kp, SCARG(uap, id));
    518  1.3   thorpej 	if (ks == NULL) {
    519  1.3   thorpej 		lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    520  1.3   thorpej 		return (EINVAL);
    521  1.3   thorpej 	}
    522  1.3   thorpej 
    523  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    524  1.3   thorpej 	if (ks->ks_name == NULL) {
    525  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    526  1.3   thorpej 		lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    527  1.3   thorpej 		return (EINVAL);
    528  1.3   thorpej 	}
    529  1.3   thorpej 
    530  1.3   thorpej 	ksr = ksem_drop_proc(kp, ks);
    531  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    532  1.3   thorpej 	free(ksr, M_SEM);
    533  1.3   thorpej 
    534  1.3   thorpej 	return (0);
    535  1.1  christos }
    536  1.1  christos 
    537  1.1  christos int
    538  1.2  christos sys__ksem_post(struct lwp *l, void *v, register_t *retval)
    539  1.1  christos {
    540  1.2  christos 	struct sys__ksem_post_args /* {
    541  1.1  christos 		semid_t id;
    542  1.1  christos 	} */ *uap = v;
    543  1.3   thorpej 	struct ksem_proc *kp;
    544  1.1  christos 	struct ksem *ks;
    545  1.1  christos 	int error;
    546  1.1  christos 
    547  1.3   thorpej 	if ((kp = l->l_proc->p_ksems) == NULL)
    548  1.3   thorpej 		return (EINVAL);
    549  1.3   thorpej 
    550  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_SHARED, NULL);
    551  1.3   thorpej 	ks = ksem_lookup_proc(kp, SCARG(uap, id));
    552  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    553  1.3   thorpej 	if (ks == NULL)
    554  1.3   thorpej 		return (EINVAL);
    555  1.3   thorpej 
    556  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    557  1.1  christos 	if (ks->ks_value == SEM_VALUE_MAX) {
    558  1.1  christos 		error = EOVERFLOW;
    559  1.3   thorpej 		goto out;
    560  1.1  christos 	}
    561  1.1  christos 	++ks->ks_value;
    562  1.3   thorpej 	if (ks->ks_waiters)
    563  1.1  christos 		wakeup(ks);
    564  1.1  christos 	error = 0;
    565  1.3   thorpej  out:
    566  1.3   thorpej 	simple_unlock(&ks->ks_interlock);
    567  1.3   thorpej 	return (error);
    568  1.3   thorpej }
    569  1.3   thorpej 
    570  1.3   thorpej static int
    571  1.3   thorpej ksem_wait(struct lwp *l, semid_t id, int tryflag)
    572  1.3   thorpej {
    573  1.3   thorpej 	struct ksem_proc *kp;
    574  1.3   thorpej 	struct ksem *ks;
    575  1.3   thorpej 	int error;
    576  1.3   thorpej 
    577  1.3   thorpej 	if ((kp = l->l_proc->p_ksems) == NULL)
    578  1.3   thorpej 		return (EINVAL);
    579  1.3   thorpej 
    580  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_SHARED, NULL);
    581  1.3   thorpej 	ks = ksem_lookup_proc(kp, id);
    582  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    583  1.3   thorpej 	if (ks == NULL)
    584  1.3   thorpej 		return (EINVAL);
    585  1.3   thorpej 
    586  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    587  1.3   thorpej 	ksem_addref(ks);
    588  1.3   thorpej 	while (ks->ks_value == 0) {
    589  1.3   thorpej 		ks->ks_waiters++;
    590  1.3   thorpej 		error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
    591  1.3   thorpej 		    &ks->ks_interlock);
    592  1.3   thorpej 		ks->ks_waiters--;
    593  1.3   thorpej 		if (error)
    594  1.3   thorpej 			goto out;
    595  1.3   thorpej 	}
    596  1.3   thorpej 	ks->ks_value--;
    597  1.3   thorpej 	error = 0;
    598  1.3   thorpej  out:
    599  1.3   thorpej 	ksem_delref(ks);
    600  1.1  christos 	return (error);
    601  1.1  christos }
    602  1.1  christos 
    603  1.1  christos int
    604  1.2  christos sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
    605  1.1  christos {
    606  1.2  christos 	struct sys__ksem_wait_args /* {
    607  1.1  christos 		semid_t id;
    608  1.1  christos 	} */ *uap = v;
    609  1.1  christos 
    610  1.1  christos 	return ksem_wait(l, SCARG(uap, id), 0);
    611  1.1  christos }
    612  1.1  christos 
    613  1.1  christos int
    614  1.2  christos sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
    615  1.1  christos {
    616  1.2  christos 	struct sys__ksem_trywait_args /* {
    617  1.1  christos 		semid_t id;
    618  1.1  christos 	} */ *uap = v;
    619  1.1  christos 
    620  1.1  christos 	return ksem_wait(l, SCARG(uap, id), 1);
    621  1.1  christos }
    622  1.1  christos 
    623  1.1  christos int
    624  1.2  christos sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
    625  1.1  christos {
    626  1.2  christos 	struct sys__ksem_getvalue_args /* {
    627  1.1  christos 		semid_t id;
    628  1.1  christos 		unsigned int *value;
    629  1.1  christos 	} */ *uap = v;
    630  1.3   thorpej 	struct ksem_proc *kp;
    631  1.1  christos 	struct ksem *ks;
    632  1.1  christos 	unsigned int val;
    633  1.1  christos 
    634  1.3   thorpej 	if ((kp = l->l_proc->p_ksems) == NULL)
    635  1.3   thorpej 		return (EINVAL);
    636  1.3   thorpej 
    637  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_SHARED, NULL);
    638  1.3   thorpej 	ks = ksem_lookup_proc(kp, SCARG(uap, id));
    639  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    640  1.3   thorpej 	if (ks == NULL)
    641  1.1  christos 		return (EINVAL);
    642  1.3   thorpej 
    643  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    644  1.1  christos 	val = ks->ks_value;
    645  1.3   thorpej 	simple_unlock(&ks->ks_interlock);
    646  1.3   thorpej 
    647  1.3   thorpej 	return (copyout(&val, SCARG(uap, value), sizeof(val)));
    648  1.1  christos }
    649  1.1  christos 
    650  1.1  christos int
    651  1.2  christos sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
    652  1.1  christos {
    653  1.2  christos 	struct sys__ksem_destroy_args /*{
    654  1.1  christos 		semid_t id;
    655  1.1  christos 	} */ *uap = v;
    656  1.3   thorpej 	struct ksem_proc *kp;
    657  1.3   thorpej 	struct ksem_ref *ksr;
    658  1.1  christos 	struct ksem *ks;
    659  1.1  christos 
    660  1.3   thorpej 	if ((kp = l->l_proc->p_ksems) == NULL)
    661  1.3   thorpej 		return (EINVAL);
    662  1.3   thorpej 
    663  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_EXCLUSIVE, NULL);
    664  1.3   thorpej 
    665  1.3   thorpej 	ks = ksem_lookup_proc(kp, SCARG(uap, id));
    666  1.3   thorpej 	if (ks == NULL) {
    667  1.3   thorpej 		lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    668  1.3   thorpej 		return (EINVAL);
    669  1.3   thorpej 	}
    670  1.3   thorpej 
    671  1.3   thorpej 	LOCK_ASSERT(simple_lock_held(&ks->ks_interlock));
    672  1.3   thorpej 
    673  1.3   thorpej 	/*
    674  1.3   thorpej 	 * XXX This misses named semaphores which have been unlink'd,
    675  1.3   thorpej 	 * XXX but since behavior of destroying a named semaphore is
    676  1.3   thorpej 	 * XXX undefined, this is technically allowed.
    677  1.3   thorpej 	 */
    678  1.3   thorpej 	if (ks->ks_name != NULL) {
    679  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    680  1.3   thorpej 		lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    681  1.3   thorpej 		return (EINVAL);
    682  1.3   thorpej 	}
    683  1.3   thorpej 
    684  1.3   thorpej 	if (ks->ks_waiters) {
    685  1.3   thorpej 		simple_unlock(&ks->ks_interlock);
    686  1.3   thorpej 		lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    687  1.3   thorpej 		return (EBUSY);
    688  1.3   thorpej 	}
    689  1.3   thorpej 
    690  1.3   thorpej 	ksr = ksem_drop_proc(kp, ks);
    691  1.3   thorpej 	lockmgr(&kp->kp_lock, LK_RELEASE, NULL);
    692  1.3   thorpej 	free(ksr, M_SEM);
    693  1.3   thorpej 
    694  1.3   thorpej 	return (0);
    695  1.3   thorpej }
    696  1.3   thorpej 
    697  1.3   thorpej static void
    698  1.3   thorpej ksem_forkhook(struct proc *p2, struct proc *p1)
    699  1.3   thorpej {
    700  1.3   thorpej 	struct ksem_proc *kp1, *kp2;
    701  1.3   thorpej 	struct ksem_ref *ksr, *ksr1;
    702  1.3   thorpej 
    703  1.3   thorpej 	if ((kp1 = p1->p_ksems) == NULL) {
    704  1.3   thorpej 		p2->p_ksems = NULL;
    705  1.3   thorpej 		return;
    706  1.3   thorpej 	}
    707  1.3   thorpej 
    708  1.3   thorpej 	p2->p_ksems = kp2 = ksem_proc_alloc();
    709  1.3   thorpej 
    710  1.3   thorpej 	lockmgr(&kp1->kp_lock, LK_SHARED, NULL);
    711  1.3   thorpej 
    712  1.3   thorpej 	if (!LIST_EMPTY(&kp1->kp_ksems)) {
    713  1.3   thorpej 		LIST_FOREACH(ksr, &kp1->kp_ksems, ksr_list) {
    714  1.3   thorpej 			ksr1 = malloc(sizeof(*ksr), M_SEM, M_WAITOK);
    715  1.3   thorpej 			ksr1->ksr_ksem = ksr->ksr_ksem;
    716  1.3   thorpej 			simple_lock(&ksr->ksr_ksem->ks_interlock);
    717  1.3   thorpej 			ksem_addref(ksr->ksr_ksem);
    718  1.3   thorpej 			simple_unlock(&ksr->ksr_ksem->ks_interlock);
    719  1.3   thorpej 			LIST_INSERT_HEAD(&kp2->kp_ksems, ksr1, ksr_list);
    720  1.3   thorpej 		}
    721  1.1  christos 	}
    722  1.3   thorpej 
    723  1.3   thorpej 	lockmgr(&kp1->kp_lock, LK_RELEASE, NULL);
    724  1.1  christos }
    725  1.1  christos 
    726  1.1  christos static void
    727  1.1  christos ksem_exithook(struct proc *p, void *arg)
    728  1.1  christos {
    729  1.3   thorpej 	struct ksem_proc *kp;
    730  1.3   thorpej 	struct ksem_ref *ksr;
    731  1.3   thorpej 
    732  1.3   thorpej 	if ((kp = p->p_ksems) == NULL)
    733  1.3   thorpej 		return;
    734  1.1  christos 
    735  1.3   thorpej 	/* Don't bother locking; process is dying. */
    736  1.3   thorpej 
    737  1.3   thorpej 	while ((ksr = LIST_FIRST(&kp->kp_ksems)) != NULL) {
    738  1.3   thorpej 		LIST_REMOVE(ksr, ksr_list);
    739  1.3   thorpej 		simple_lock(&ksr->ksr_ksem->ks_interlock);
    740  1.3   thorpej 		ksem_delref(ksr->ksr_ksem);
    741  1.3   thorpej 		free(ksr, M_SEM);
    742  1.1  christos 	}
    743  1.1  christos }
    744  1.1  christos 
    745  1.1  christos void
    746  1.1  christos ksem_init(void)
    747  1.1  christos {
    748  1.3   thorpej 
    749  1.1  christos 	simple_lock_init(&ksem_slock);
    750  1.1  christos 	exithook_establish(ksem_exithook, NULL);
    751  1.1  christos 	exechook_establish(ksem_exithook, NULL);
    752  1.3   thorpej 	forkhook_establish(ksem_forkhook);
    753  1.1  christos }
    754