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