Home | History | Annotate | Line # | Download | only in kern
uipc_sem.c revision 1.2
      1 /* $NetBSD: uipc_sem.c,v 1.2 2003/01/20 20:24:22 christos Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2002 Alfred Perlstein <alfred (at) FreeBSD.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  *
     28  *	$FreeBSD: src/sys/kern/uipc_sem.c,v 1.4 2003/01/10 23:13:16 alfred Exp $
     29  */
     30 
     31 #include "opt_posix.h"
     32 
     33 #include <sys/param.h>
     34 #include <sys/systm.h>
     35 #include <sys/kernel.h>
     36 #include <sys/proc.h>
     37 #include <sys/lock.h>
     38 #include <sys/ksem.h>
     39 #include <sys/syscall.h>
     40 #include <sys/stat.h>
     41 #include <sys/malloc.h>
     42 #include <sys/fcntl.h>
     43 
     44 #include <sys/mount.h>
     45 
     46 #include <sys/syscallargs.h>
     47 
     48 #ifndef SEM_MAX
     49 #define SEM_MAX	30
     50 #endif
     51 
     52 #define SEM_MAX_NAMELEN	14
     53 #define SEM_VALUE_MAX (~0U)
     54 
     55 #define SEM_TO_ID(x)	((intptr_t)(x))
     56 #define ID_TO_SEM(x)	ksem_id_to_sem(x)
     57 
     58 struct kuser {
     59 	pid_t ku_pid;
     60 	LIST_ENTRY(kuser) ku_next;
     61 };
     62 
     63 /* For sysctl eventually */
     64 int nsems = 0;
     65 
     66 struct ksem {
     67 	LIST_ENTRY(ksem) ks_entry;	/* global list entry */
     68 	int ks_onlist;			/* boolean if on a list (ks_entry) */
     69 	char *ks_name;			/* if named, this is the name */
     70 	int ks_ref;			/* number of references */
     71 	mode_t ks_mode;			/* protection bits */
     72 	uid_t ks_uid;			/* creator uid */
     73 	gid_t ks_gid;			/* creator gid */
     74 	unsigned int ks_value;		/* current value */
     75 	int ks_waiters;			/* number of waiters */
     76 	LIST_HEAD(, kuser) ks_users;	/* pids using this sem */
     77 };
     78 
     79 /*
     80  * available semaphores go here, this includes sys__ksem_init and any semaphores
     81  * created via sys__ksem_open that have not yet been unlinked.
     82  */
     83 LIST_HEAD(, ksem) ksem_head = LIST_HEAD_INITIALIZER(&ksem_head);
     84 /*
     85  * semaphores still in use but have been ksem_unlink()'d go here.
     86  */
     87 LIST_HEAD(, ksem) ksem_deadhead = LIST_HEAD_INITIALIZER(&ksem_deadhead);
     88 
     89 static struct simplelock ksem_slock;
     90 
     91 #ifdef SEM_DEBUG
     92 #define DP(x)	printf x
     93 #else
     94 #define DP(x)
     95 #endif
     96 
     97 static __inline void ksem_ref(struct ksem *ks);
     98 static __inline void ksem_rel(struct ksem *ks);
     99 static __inline struct ksem *ksem_id_to_sem(semid_t id);
    100 static __inline struct kuser *ksem_getuser(struct proc *p, struct ksem *ks);
    101 
    102 static struct ksem *ksem_lookup_byname(const char *name);
    103 static int ksem_create(struct lwp *l, const char *name,
    104     struct ksem **ksret, mode_t mode, unsigned int value);
    105 static void ksem_free(struct ksem *ksnew);
    106 static int ksem_perm(struct proc *p, struct ksem *ks);
    107 static void ksem_enter(struct proc *p, struct ksem *ks);
    108 static int ksem_leave(struct proc *p, struct ksem *ks);
    109 static void ksem_exithook(struct proc *p, void *arg);
    110 static int ksem_hasopen(struct proc *p, struct ksem *ks);
    111 static int ksem_wait(struct lwp *l, semid_t id, int tryflag);
    112 
    113 
    114 static __inline void
    115 ksem_ref(struct ksem *ks)
    116 {
    117 
    118 	ks->ks_ref++;
    119 	DP(("ksem_ref: ks = %p, ref = %d\n", ks, ks->ks_ref));
    120 }
    121 
    122 static __inline void
    123 ksem_rel(struct ksem *ks)
    124 {
    125 
    126 	DP(("ksem_rel: ks = %p, ref = %d\n", ks, ks->ks_ref - 1));
    127 	if (--ks->ks_ref == 0)
    128 		ksem_free(ks);
    129 }
    130 
    131 static __inline struct ksem *
    132 ksem_id_to_sem(id)
    133 	semid_t id;
    134 {
    135 	struct ksem *ks;
    136 
    137 	DP(("id_to_sem: id = 0x%ld\n", id));
    138 	LIST_FOREACH(ks, &ksem_head, ks_entry) {
    139 		DP(("id_to_sem: ks = %p\n", ks));
    140 		if (ks == (struct ksem *)id)
    141 			return (ks);
    142 	}
    143 	return (NULL);
    144 }
    145 
    146 static struct ksem *
    147 ksem_lookup_byname(name)
    148 	const char *name;
    149 {
    150 	struct ksem *ks;
    151 
    152 	LIST_FOREACH(ks, &ksem_head, ks_entry)
    153 		if (ks->ks_name != NULL && strcmp(ks->ks_name, name) == 0)
    154 			return (ks);
    155 	return (NULL);
    156 }
    157 
    158 static int
    159 ksem_create(l, name, ksret, mode, value)
    160 	struct lwp *l;
    161 	const char *name;
    162 	struct ksem **ksret;
    163 	mode_t mode;
    164 	unsigned int value;
    165 {
    166 	struct ksem *ret;
    167 	struct proc *p;
    168 	struct ucred *uc;
    169 	size_t len;
    170 	int error;
    171 
    172 	DP(("ksem_create %s %p %d %u\n", name ? name : "(null)", ksret, mode,
    173 	    value));
    174 	p = l->l_proc;
    175 	uc = p->p_ucred;
    176 	if (value > SEM_VALUE_MAX)
    177 		return (EINVAL);
    178 	ret = malloc(sizeof(*ret), M_SEM, M_WAITOK | M_ZERO);
    179 	if (name != NULL) {
    180 		len = strlen(name);
    181 		if (len > SEM_MAX_NAMELEN) {
    182 			free(ret, M_SEM);
    183 			return (ENAMETOOLONG);
    184 		}
    185 		/* name must start with a '/' but not contain one. */
    186 		if (*name != '/' || len < 2 || strchr(name + 1, '/') != NULL) {
    187 			free(ret, M_SEM);
    188 			return (EINVAL);
    189 		}
    190 		ret->ks_name = malloc(len + 1, M_SEM, M_WAITOK);
    191 		strcpy(ret->ks_name, name);
    192 	} else {
    193 		ret->ks_name = NULL;
    194 	}
    195 	ret->ks_mode = mode;
    196 	ret->ks_value = value;
    197 	ret->ks_ref = 1;
    198 	ret->ks_waiters = 0;
    199 	ret->ks_uid = uc->cr_uid;
    200 	ret->ks_gid = uc->cr_gid;
    201 	ret->ks_onlist = 0;
    202 	LIST_INIT(&ret->ks_users);
    203 	if (name != NULL)
    204 		ksem_enter(l->l_proc, ret);
    205 	*ksret = ret;
    206 	simple_lock(&ksem_slock);
    207 	if (nsems >= SEM_MAX) {
    208 		ksem_leave(l->l_proc, ret);
    209 		ksem_free(ret);
    210 		error = ENFILE;
    211 	} else {
    212 		nsems++;
    213 		error = 0;
    214 	}
    215 	simple_unlock(&ksem_slock);
    216 	return (error);
    217 }
    218 
    219 int
    220 sys__ksem_init(struct lwp *l, void *v, register_t *retval)
    221 {
    222 	struct sys__ksem_init_args /* {
    223 		unsigned int value;
    224 		semid_t *idp;
    225 	} */ *uap = v;
    226 	struct ksem *ks;
    227 	semid_t id;
    228 	int error;
    229 
    230 	error = ksem_create(l, NULL, &ks, S_IRWXU | S_IRWXG, SCARG(uap, value));
    231 	if (error)
    232 		return (error);
    233 	id = SEM_TO_ID(ks);
    234 	error = copyout(&id, SCARG(uap, idp), sizeof(id));
    235 	if (error) {
    236 		simple_lock(&ksem_slock);
    237 		ksem_rel(ks);
    238 		simple_unlock(&ksem_slock);
    239 		return (error);
    240 	}
    241 	simple_lock(&ksem_slock);
    242 	LIST_INSERT_HEAD(&ksem_head, ks, ks_entry);
    243 	ks->ks_onlist = 1;
    244 	simple_unlock(&ksem_slock);
    245 	return (error);
    246 }
    247 
    248 int
    249 sys__ksem_open(struct lwp *l, void *v, register_t *retval)
    250 {
    251 	struct sys__ksem_open_args /* {
    252 		const char *name;
    253 		int oflag;
    254 		mode_t mode;
    255 		unsigned int value;
    256 		semid_t *idp;
    257 	} */ *uap = v;
    258 	char name[SEM_MAX_NAMELEN + 1];
    259 	size_t done;
    260 	int error;
    261 	struct ksem *ksnew, *ks;
    262 	semid_t id;
    263 
    264 	error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
    265 	if (error)
    266 		return (error);
    267 
    268 	ksnew = NULL;
    269 	simple_lock(&ksem_slock);
    270 	ks = ksem_lookup_byname(name);
    271 	/*
    272 	 * If we found it but O_EXCL is set, error.
    273 	 */
    274 	if (ks != NULL && (SCARG(uap, oflag) & O_EXCL) != 0) {
    275 		simple_unlock(&ksem_slock);
    276 		return (EEXIST);
    277 	}
    278 	/*
    279 	 * If we didn't find it...
    280 	 */
    281 	if (ks == NULL) {
    282 		/*
    283 		 * didn't ask for creation? error.
    284 		 */
    285 		if ((SCARG(uap, oflag) & O_CREAT) == 0) {
    286 			simple_unlock(&ksem_slock);
    287 			return (ENOENT);
    288 		}
    289 		/*
    290 		 * We may block during creation, so drop the lock.
    291 		 */
    292 		simple_unlock(&ksem_slock);
    293 		error = ksem_create(l, name, &ksnew, SCARG(uap, mode),
    294 		    SCARG(uap, value));
    295 		if (error != 0)
    296 			return (error);
    297 		id = SEM_TO_ID(ksnew);
    298 		DP(("about to copyout! 0x%lx to %p\n", id, SCARG(uap, idp)));
    299 		error = copyout(&id, SCARG(uap, idp), sizeof(id));
    300 		if (error) {
    301 			simple_lock(&ksem_slock);
    302 			ksem_leave(l->l_proc, ksnew);
    303 			ksem_rel(ksnew);
    304 			simple_unlock(&ksem_slock);
    305 			return (error);
    306 		}
    307 		/*
    308 		 * We need to make sure we haven't lost a race while
    309 		 * allocating during creation.
    310 		 */
    311 		simple_lock(&ksem_slock);
    312 		ks = ksem_lookup_byname(name);
    313 		if (ks != NULL) {
    314 			/* we lost... */
    315 			ksem_leave(l->l_proc, ksnew);
    316 			ksem_rel(ksnew);
    317 			/* we lost and we can't loose... */
    318 			if ((SCARG(uap, oflag) & O_EXCL) != 0) {
    319 				simple_unlock(&ksem_slock);
    320 				return (EEXIST);
    321 			}
    322 		} else {
    323 			DP(("ksem_create: about to add to list...\n"));
    324 			LIST_INSERT_HEAD(&ksem_head, ksnew, ks_entry);
    325 			DP(("ksem_create: setting list bit...\n"));
    326 			ksnew->ks_onlist = 1;
    327 			DP(("ksem_create: done, about to unlock...\n"));
    328 		}
    329 		simple_unlock(&ksem_slock);
    330 	} else {
    331 		/*
    332 		 * if we aren't the creator, then enforce permissions.
    333 		 */
    334 		error = ksem_perm(l->l_proc, ks);
    335 		if (!error)
    336 			ksem_ref(ks);
    337 		simple_unlock(&ksem_slock);
    338 		if (error)
    339 			return (error);
    340 		id = SEM_TO_ID(ks);
    341 		error = copyout(&id, SCARG(uap, idp), sizeof(id));
    342 		if (error) {
    343 			simple_lock(&ksem_slock);
    344 			ksem_rel(ks);
    345 			simple_unlock(&ksem_slock);
    346 			return (error);
    347 		}
    348 		ksem_enter(l->l_proc, ks);
    349 		simple_lock(&ksem_slock);
    350 		ksem_rel(ks);
    351 		simple_unlock(&ksem_slock);
    352 	}
    353 	return (error);
    354 }
    355 
    356 static int
    357 ksem_perm(p, ks)
    358 	struct proc *p;
    359 	struct ksem *ks;
    360 {
    361 	struct ucred *uc;
    362 
    363 	uc = p->p_ucred;
    364 	DP(("ksem_perm: uc(%d,%d) ks(%d,%d,%o)\n",
    365 	    uc->cr_uid, uc->cr_gid,
    366 	     ks->ks_uid, ks->ks_gid, ks->ks_mode));
    367 	if ((uc->cr_uid == ks->ks_uid && (ks->ks_mode & S_IWUSR) != 0) ||
    368 	    (uc->cr_gid == ks->ks_gid && (ks->ks_mode & S_IWGRP) != 0) ||
    369 	    (ks->ks_mode & S_IWOTH) != 0 || suser(uc, &p->p_acflag) == 0)
    370 		return (0);
    371 	return (EPERM);
    372 }
    373 
    374 static void
    375 ksem_free(struct ksem *ks)
    376 {
    377 	nsems--;
    378 	if (ks->ks_onlist)
    379 		LIST_REMOVE(ks, ks_entry);
    380 	if (ks->ks_name != NULL)
    381 		free(ks->ks_name, M_SEM);
    382 	free(ks, M_SEM);
    383 }
    384 
    385 static __inline struct kuser *
    386 ksem_getuser(struct proc *p, struct ksem *ks)
    387 {
    388 	struct kuser *k;
    389 
    390 	LIST_FOREACH(k, &ks->ks_users, ku_next)
    391 		if (k->ku_pid == p->p_pid)
    392 			return (k);
    393 	return (NULL);
    394 }
    395 
    396 static int
    397 ksem_hasopen(struct proc *p, struct ksem *ks)
    398 {
    399 
    400 	return ((ks->ks_name == NULL && ksem_perm(p, ks))
    401 	    || ksem_getuser(p, ks) != NULL);
    402 }
    403 
    404 static int
    405 ksem_leave(struct proc *p, struct ksem *ks)
    406 {
    407 	struct kuser *k;
    408 
    409 	DP(("ksem_leave: ks = %p\n", ks));
    410 	k = ksem_getuser(p, ks);
    411 	DP(("ksem_leave: ks = %p, k = %p\n", ks, k));
    412 	if (k != NULL) {
    413 		LIST_REMOVE(k, ku_next);
    414 		ksem_rel(ks);
    415 		DP(("ksem_leave: about to free k\n"));
    416 		free(k, M_SEM);
    417 		DP(("ksem_leave: returning\n"));
    418 		return (0);
    419 	}
    420 	return (EINVAL);
    421 }
    422 
    423 static void
    424 ksem_enter(struct proc *p, struct ksem *ks)
    425 {
    426 	struct kuser *ku, *k;
    427 
    428 	ku = malloc(sizeof(*ku), M_SEM, M_WAITOK);
    429 	ku->ku_pid = p->p_pid;
    430 	simple_lock(&ksem_slock);
    431 	k = ksem_getuser(p, ks);
    432 	if (k != NULL) {
    433 		simple_unlock(&ksem_slock);
    434 		free(ku, M_TEMP);
    435 		return;
    436 	}
    437 	LIST_INSERT_HEAD(&ks->ks_users, ku, ku_next);
    438 	ksem_ref(ks);
    439 	simple_unlock(&ksem_slock);
    440 }
    441 
    442 int
    443 sys__ksem_unlink(struct lwp *l, void *v, register_t *retval)
    444 {
    445 	struct sys__ksem_unlink_args /* {
    446 		const char *name;
    447 	} */ *uap = v;
    448 	char name[SEM_MAX_NAMELEN + 1];
    449 	size_t done;
    450 	struct ksem *ks;
    451 	int error;
    452 
    453 	error = copyinstr(SCARG(uap, name), name, sizeof(name), &done);
    454 	if (error)
    455 		return error;
    456 
    457 	simple_lock(&ksem_slock);
    458 	ks = ksem_lookup_byname(name);
    459 	if (ks == NULL)
    460 		error = ENOENT;
    461 	else
    462 		error = ksem_perm(l->l_proc, ks);
    463 	DP(("ksem_unlink: '%s' ks = %p, error = %d\n", name, ks, error));
    464 	if (error == 0) {
    465 		LIST_REMOVE(ks, ks_entry);
    466 		LIST_INSERT_HEAD(&ksem_deadhead, ks, ks_entry);
    467 		ksem_rel(ks);
    468 	}
    469 	simple_unlock(&ksem_slock);
    470 	return (error);
    471 }
    472 
    473 int
    474 sys__ksem_close(struct lwp *l, void *v, register_t *retval)
    475 {
    476 	struct sys__ksem_close_args /* {
    477 		semid_t id;
    478 	} */ *uap = v;
    479 	struct ksem *ks;
    480 	int error;
    481 
    482 	error = EINVAL;
    483 	simple_lock(&ksem_slock);
    484 	ks = ID_TO_SEM(SCARG(uap, id));
    485 	/* this is not a valid operation for unnamed sems */
    486 	if (ks != NULL && ks->ks_name != NULL)
    487 		error = ksem_leave(l->l_proc, ks);
    488 	simple_unlock(&ksem_slock);
    489 	return (error);
    490 }
    491 
    492 int
    493 sys__ksem_post(struct lwp *l, void *v, register_t *retval)
    494 {
    495 	struct sys__ksem_post_args /* {
    496 		semid_t id;
    497 	} */ *uap = v;
    498 	struct ksem *ks;
    499 	int error;
    500 
    501 	simple_lock(&ksem_slock);
    502 	ks = ID_TO_SEM(SCARG(uap, id));
    503 	if (ks == NULL || !ksem_hasopen(l->l_proc, ks)) {
    504 		error = EINVAL;
    505 		goto err;
    506 	}
    507 	if (ks->ks_value == SEM_VALUE_MAX) {
    508 		error = EOVERFLOW;
    509 		goto err;
    510 	}
    511 	++ks->ks_value;
    512 	if (ks->ks_waiters > 0)
    513 		wakeup(ks);
    514 	error = 0;
    515 err:
    516 	simple_unlock(&ksem_slock);
    517 	return (error);
    518 }
    519 
    520 int
    521 sys__ksem_wait(struct lwp *l, void *v, register_t *retval)
    522 {
    523 	struct sys__ksem_wait_args /* {
    524 		semid_t id;
    525 	} */ *uap = v;
    526 
    527 	return ksem_wait(l, SCARG(uap, id), 0);
    528 }
    529 
    530 int
    531 sys__ksem_trywait(struct lwp *l, void *v, register_t *retval)
    532 {
    533 	struct sys__ksem_trywait_args /* {
    534 		semid_t id;
    535 	} */ *uap = v;
    536 
    537 	return ksem_wait(l, SCARG(uap, id), 1);
    538 }
    539 
    540 static int
    541 ksem_wait(struct lwp *l, semid_t id, int tryflag)
    542 {
    543 	struct ksem *ks;
    544 	int error;
    545 
    546 	DP((">>> kern_sem_wait entered!\n"));
    547 	simple_lock(&ksem_slock);
    548 	ks = ID_TO_SEM(id);
    549 	if (ks == NULL) {
    550 		DP(("kern_sem_wait ks == NULL\n"));
    551 		error = EINVAL;
    552 		goto err;
    553 	}
    554 	ksem_ref(ks);
    555 	if (!ksem_hasopen(l->l_proc, ks)) {
    556 		DP(("kern_sem_wait hasopen failed\n"));
    557 		error = EINVAL;
    558 		goto err;
    559 	}
    560 	DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
    561 	if (ks->ks_value == 0) {
    562 		ks->ks_waiters++;
    563 		error = tryflag ? EAGAIN : ltsleep(ks, PCATCH, "psem", 0,
    564 		    &ksem_slock);
    565 		ks->ks_waiters--;
    566 		if (error)
    567 			goto err;
    568 	}
    569 	ks->ks_value--;
    570 	error = 0;
    571 err:
    572 	if (ks != NULL)
    573 		ksem_rel(ks);
    574 	simple_unlock(&ksem_slock);
    575 	DP(("<<< kern_sem_wait leaving, error = %d\n", error));
    576 	return (error);
    577 }
    578 
    579 int
    580 sys__ksem_getvalue(struct lwp *l, void *v, register_t *retval)
    581 {
    582 	struct sys__ksem_getvalue_args /* {
    583 		semid_t id;
    584 		unsigned int *value;
    585 	} */ *uap = v;
    586 	struct ksem *ks;
    587 	unsigned int val;
    588 
    589 	simple_lock(&ksem_slock);
    590 	ks = ID_TO_SEM(SCARG(uap, id));
    591 	if (ks == NULL || !ksem_hasopen(l->l_proc, ks)) {
    592 		simple_unlock(&ksem_slock);
    593 		return (EINVAL);
    594 	}
    595 	val = ks->ks_value;
    596 	simple_unlock(&ksem_slock);
    597 	return copyout(&val, SCARG(uap, value), sizeof(val));
    598 }
    599 
    600 int
    601 sys__ksem_destroy(struct lwp *l, void *v, register_t *retval)
    602 {
    603 	struct sys__ksem_destroy_args /*{
    604 		semid_t id;
    605 	} */ *uap = v;
    606 	struct ksem *ks;
    607 	int error;
    608 
    609 	simple_lock(&ksem_slock);
    610 	ks = ID_TO_SEM(SCARG(uap, id));
    611 	if (ks == NULL || !ksem_hasopen(l->l_proc, ks) ||
    612 	    ks->ks_name != NULL) {
    613 		error = EINVAL;
    614 		goto err;
    615 	}
    616 	if (ks->ks_waiters != 0) {
    617 		error = EBUSY;
    618 		goto err;
    619 	}
    620 	ksem_rel(ks);
    621 	error = 0;
    622 err:
    623 	simple_unlock(&ksem_slock);
    624 	return (error);
    625 }
    626 
    627 static void
    628 ksem_exithook(struct proc *p, void *arg)
    629 {
    630 	struct ksem *ks, *ksnext;
    631 
    632 	simple_lock(&ksem_slock);
    633 	ks = LIST_FIRST(&ksem_head);
    634 	while (ks != NULL) {
    635 		ksnext = LIST_NEXT(ks, ks_entry);
    636 		ksem_leave(p, ks);
    637 		ks = ksnext;
    638 	}
    639 	ks = LIST_FIRST(&ksem_deadhead);
    640 	while (ks != NULL) {
    641 		ksnext = LIST_NEXT(ks, ks_entry);
    642 		ksem_leave(p, ks);
    643 		ks = ksnext;
    644 	}
    645 	simple_unlock(&ksem_slock);
    646 }
    647 
    648 void
    649 ksem_init(void)
    650 {
    651 	simple_lock_init(&ksem_slock);
    652 	exithook_establish(ksem_exithook, NULL);
    653 	exechook_establish(ksem_exithook, NULL);
    654 }
    655