1139804Simp/*- 281645Sjasone * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. All rights reserved. 381645Sjasone * 481645Sjasone * Redistribution and use in source and binary forms, with or without 581645Sjasone * modification, are permitted provided that the following conditions 681645Sjasone * are met: 781645Sjasone * 1. Redistributions of source code must retain the above copyright 881645Sjasone * notice(s), this list of conditions and the following disclaimer as 981645Sjasone * the first lines of this file unmodified other than the possible 1081645Sjasone * addition of one or more copyright notices. 1181645Sjasone * 2. Redistributions in binary form must reproduce the above copyright 1281645Sjasone * notice(s), this list of conditions and the following disclaimer in the 1381645Sjasone * documentation and/or other materials provided with the distribution. 1481645Sjasone * 1581645Sjasone * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 1681645Sjasone * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1781645Sjasone * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1881645Sjasone * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 1981645Sjasone * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2081645Sjasone * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2181645Sjasone * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2281645Sjasone * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2381645Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2481645Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 2581645Sjasone * DAMAGE. 2681645Sjasone */ 2781645Sjasone 2881645Sjasone/* 2981645Sjasone * Counting semaphores. 3081645Sjasone * 3181645Sjasone * Priority propagation will not generally raise the priority of semaphore 3281645Sjasone * "owners" (a misnomer in the context of semaphores), so should not be relied 3381645Sjasone * upon in combination with semaphores. 3481645Sjasone */ 3581645Sjasone 36116182Sobrien#include <sys/cdefs.h> 37116182Sobrien__FBSDID("$FreeBSD$"); 38116182Sobrien 3981645Sjasone#include <sys/param.h> 4081645Sjasone#include <sys/systm.h> 4181645Sjasone#include <sys/ktr.h> 4281645Sjasone#include <sys/condvar.h> 4381645Sjasone#include <sys/lock.h> 4481645Sjasone#include <sys/mutex.h> 4581645Sjasone#include <sys/sema.h> 4681645Sjasone 4781645Sjasonevoid 4881645Sjasonesema_init(struct sema *sema, int value, const char *description) 4981645Sjasone{ 5081645Sjasone 5181645Sjasone KASSERT((value >= 0), ("%s(): negative value\n", __func__)); 5281645Sjasone 5381645Sjasone bzero(sema, sizeof(*sema)); 5493818Sjhb mtx_init(&sema->sema_mtx, description, "sema backing lock", 5581645Sjasone MTX_DEF | MTX_NOWITNESS | MTX_QUIET); 5681645Sjasone cv_init(&sema->sema_cv, description); 5781645Sjasone sema->sema_value = value; 5881645Sjasone 5987593Sobrien CTR4(KTR_LOCK, "%s(%p, %d, \"%s\")", __func__, sema, value, description); 6081645Sjasone} 6181645Sjasone 6281645Sjasonevoid 6381645Sjasonesema_destroy(struct sema *sema) 6481645Sjasone{ 6581645Sjasone 6687593Sobrien CTR3(KTR_LOCK, "%s(%p) \"%s\"", __func__, sema, 6781645Sjasone cv_wmesg(&sema->sema_cv)); 6881645Sjasone 6981645Sjasone KASSERT((sema->sema_waiters == 0), ("%s(): waiters\n", __func__)); 7081645Sjasone 7181645Sjasone mtx_destroy(&sema->sema_mtx); 7281645Sjasone cv_destroy(&sema->sema_cv); 7381645Sjasone} 7481645Sjasone 7581645Sjasonevoid 7681645Sjasone_sema_post(struct sema *sema, const char *file, int line) 7781645Sjasone{ 7881645Sjasone 7981645Sjasone mtx_lock(&sema->sema_mtx); 8081645Sjasone sema->sema_value++; 8181645Sjasone if (sema->sema_waiters && sema->sema_value > 0) 8281645Sjasone cv_signal(&sema->sema_cv); 8381645Sjasone 8487593Sobrien CTR6(KTR_LOCK, "%s(%p) \"%s\" v = %d at %s:%d", __func__, sema, 8581645Sjasone cv_wmesg(&sema->sema_cv), sema->sema_value, file, line); 8681645Sjasone 8781645Sjasone mtx_unlock(&sema->sema_mtx); 8881645Sjasone} 8981645Sjasone 9081645Sjasonevoid 9181645Sjasone_sema_wait(struct sema *sema, const char *file, int line) 9281645Sjasone{ 9381645Sjasone 9481645Sjasone mtx_lock(&sema->sema_mtx); 9581645Sjasone while (sema->sema_value == 0) { 9681645Sjasone sema->sema_waiters++; 9781645Sjasone cv_wait(&sema->sema_cv, &sema->sema_mtx); 9881645Sjasone sema->sema_waiters--; 9981645Sjasone } 10081645Sjasone sema->sema_value--; 10181645Sjasone 10287593Sobrien CTR6(KTR_LOCK, "%s(%p) \"%s\" v = %d at %s:%d", __func__, sema, 10381645Sjasone cv_wmesg(&sema->sema_cv), sema->sema_value, file, line); 10481645Sjasone 10581645Sjasone mtx_unlock(&sema->sema_mtx); 10681645Sjasone} 10781645Sjasone 10881645Sjasoneint 10981645Sjasone_sema_timedwait(struct sema *sema, int timo, const char *file, int line) 11081645Sjasone{ 111130481Sjdp int error; 11281645Sjasone 11381645Sjasone mtx_lock(&sema->sema_mtx); 11481645Sjasone 11581645Sjasone /* 11681645Sjasone * A spurious wakeup will cause the timeout interval to start over. 11781645Sjasone * This isn't a big deal as long as spurious wakeups don't occur 11881645Sjasone * continuously, since the timeout period is merely a lower bound on how 11981645Sjasone * long to wait. 12081645Sjasone */ 121130481Sjdp for (error = 0; sema->sema_value == 0 && error == 0;) { 12281645Sjasone sema->sema_waiters++; 123130481Sjdp error = cv_timedwait(&sema->sema_cv, &sema->sema_mtx, timo); 12481645Sjasone sema->sema_waiters--; 12581645Sjasone } 12681645Sjasone if (sema->sema_value > 0) { 12781645Sjasone /* Success. */ 12881645Sjasone sema->sema_value--; 129130481Sjdp error = 0; 13081645Sjasone 13187593Sobrien CTR6(KTR_LOCK, "%s(%p) \"%s\" v = %d at %s:%d", __func__, sema, 13281645Sjasone cv_wmesg(&sema->sema_cv), sema->sema_value, file, line); 13381645Sjasone } else { 13487593Sobrien CTR5(KTR_LOCK, "%s(%p) \"%s\" fail at %s:%d", __func__, sema, 13581645Sjasone cv_wmesg(&sema->sema_cv), file, line); 13681645Sjasone } 13781645Sjasone 13881645Sjasone mtx_unlock(&sema->sema_mtx); 139130481Sjdp return (error); 14081645Sjasone} 14181645Sjasone 14281645Sjasoneint 14381645Sjasone_sema_trywait(struct sema *sema, const char *file, int line) 14481645Sjasone{ 14581645Sjasone int ret; 14681645Sjasone 14781645Sjasone mtx_lock(&sema->sema_mtx); 14881645Sjasone 14981645Sjasone if (sema->sema_value > 0) { 15081645Sjasone /* Success. */ 15181645Sjasone sema->sema_value--; 15281645Sjasone ret = 1; 15381645Sjasone 15487593Sobrien CTR6(KTR_LOCK, "%s(%p) \"%s\" v = %d at %s:%d", __func__, sema, 15581645Sjasone cv_wmesg(&sema->sema_cv), sema->sema_value, file, line); 15681645Sjasone } else { 15781645Sjasone ret = 0; 15881645Sjasone 15987593Sobrien CTR5(KTR_LOCK, "%s(%p) \"%s\" fail at %s:%d", __func__, sema, 16081645Sjasone cv_wmesg(&sema->sema_cv), file, line); 16181645Sjasone } 16281645Sjasone 16381645Sjasone mtx_unlock(&sema->sema_mtx); 16481645Sjasone return (ret); 16581645Sjasone} 16681645Sjasone 16781645Sjasoneint 16881645Sjasonesema_value(struct sema *sema) 16981645Sjasone{ 17081645Sjasone int ret; 17181645Sjasone 17281645Sjasone mtx_lock(&sema->sema_mtx); 17381645Sjasone ret = sema->sema_value; 17481645Sjasone mtx_unlock(&sema->sema_mtx); 17581645Sjasone return (ret); 17681645Sjasone} 177