kern_sema.c revision 81645
181645Sjasone/*
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 * $FreeBSD: head/sys/kern/kern_sema.c 81645 2001-08-14 22:13:14Z jasone $
2881645Sjasone */
2981645Sjasone
3081645Sjasone/*
3181645Sjasone * Counting semaphores.
3281645Sjasone *
3381645Sjasone * Priority propagation will not generally raise the priority of semaphore
3481645Sjasone * "owners" (a misnomer in the context of semaphores), so should not be relied
3581645Sjasone * upon in combination with semaphores.
3681645Sjasone */
3781645Sjasone
3881645Sjasone#include <sys/param.h>
3981645Sjasone#include <sys/systm.h>
4081645Sjasone#include <sys/ktr.h>
4181645Sjasone#include <sys/condvar.h>
4281645Sjasone#include <sys/lock.h>
4381645Sjasone#include <sys/mutex.h>
4481645Sjasone#include <sys/sema.h>
4581645Sjasone
4681645Sjasonevoid
4781645Sjasonesema_init(struct sema *sema, int value, const char *description)
4881645Sjasone{
4981645Sjasone
5081645Sjasone	KASSERT((value >= 0), ("%s(): negative value\n", __func__));
5181645Sjasone
5281645Sjasone	bzero(sema, sizeof(*sema));
5381645Sjasone	mtx_init(&sema->sema_mtx, "sema backing lock",
5481645Sjasone	    MTX_DEF | MTX_NOWITNESS | MTX_QUIET);
5581645Sjasone	cv_init(&sema->sema_cv, description);
5681645Sjasone	sema->sema_value = value;
5781645Sjasone
5881645Sjasone	CTR3(KTR_LOCK, __func__ "(%p, %d, \"%s\")", sema, value, description);
5981645Sjasone}
6081645Sjasone
6181645Sjasonevoid
6281645Sjasonesema_destroy(struct sema *sema)
6381645Sjasone{
6481645Sjasone
6581645Sjasone	CTR2(KTR_LOCK, __func__ "(%p) \"%s\"", sema,
6681645Sjasone	    cv_wmesg(&sema->sema_cv));
6781645Sjasone
6881645Sjasone	KASSERT((sema->sema_waiters == 0), ("%s(): waiters\n", __func__));
6981645Sjasone
7081645Sjasone	mtx_destroy(&sema->sema_mtx);
7181645Sjasone	cv_destroy(&sema->sema_cv);
7281645Sjasone}
7381645Sjasone
7481645Sjasonevoid
7581645Sjasone_sema_post(struct sema *sema, const char *file, int line)
7681645Sjasone{
7781645Sjasone
7881645Sjasone	mtx_lock(&sema->sema_mtx);
7981645Sjasone	sema->sema_value++;
8081645Sjasone	if (sema->sema_waiters && sema->sema_value > 0)
8181645Sjasone		cv_signal(&sema->sema_cv);
8281645Sjasone
8381645Sjasone	CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
8481645Sjasone	    cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
8581645Sjasone
8681645Sjasone	mtx_unlock(&sema->sema_mtx);
8781645Sjasone}
8881645Sjasone
8981645Sjasonevoid
9081645Sjasone_sema_wait(struct sema *sema, const char *file, int line)
9181645Sjasone{
9281645Sjasone
9381645Sjasone	mtx_lock(&sema->sema_mtx);
9481645Sjasone	while (sema->sema_value == 0) {
9581645Sjasone		sema->sema_waiters++;
9681645Sjasone		cv_wait(&sema->sema_cv, &sema->sema_mtx);
9781645Sjasone		sema->sema_waiters--;
9881645Sjasone	}
9981645Sjasone	sema->sema_value--;
10081645Sjasone
10181645Sjasone	CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
10281645Sjasone	    cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
10381645Sjasone
10481645Sjasone	mtx_unlock(&sema->sema_mtx);
10581645Sjasone}
10681645Sjasone
10781645Sjasoneint
10881645Sjasone_sema_timedwait(struct sema *sema, int timo, const char *file, int line)
10981645Sjasone{
11081645Sjasone	int ret, timed_out;
11181645Sjasone
11281645Sjasone	mtx_lock(&sema->sema_mtx);
11381645Sjasone
11481645Sjasone	/*
11581645Sjasone	 * A spurious wakeup will cause the timeout interval to start over.
11681645Sjasone	 * This isn't a big deal as long as spurious wakeups don't occur
11781645Sjasone	 * continuously, since the timeout period is merely a lower bound on how
11881645Sjasone	 * long to wait.
11981645Sjasone	 */
12081645Sjasone	for (timed_out = 0; sema->sema_value == 0 && timed_out == 0;) {
12181645Sjasone		sema->sema_waiters++;
12281645Sjasone		timed_out = cv_timedwait(&sema->sema_cv, &sema->sema_mtx, timo);
12381645Sjasone		sema->sema_waiters--;
12481645Sjasone	}
12581645Sjasone	if (sema->sema_value > 0) {
12681645Sjasone		/* Success. */
12781645Sjasone		sema->sema_value--;
12881645Sjasone		ret = 1;
12981645Sjasone
13081645Sjasone		CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
13181645Sjasone		    cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
13281645Sjasone	} else {
13381645Sjasone		ret = 0;
13481645Sjasone
13581645Sjasone		CTR4(KTR_LOCK, __func__ "(%p) \"%s\" fail at %s:%d", sema,
13681645Sjasone		    cv_wmesg(&sema->sema_cv), file, line);
13781645Sjasone	}
13881645Sjasone
13981645Sjasone	mtx_unlock(&sema->sema_mtx);
14081645Sjasone	return (ret);
14181645Sjasone}
14281645Sjasone
14381645Sjasoneint
14481645Sjasone_sema_trywait(struct sema *sema, const char *file, int line)
14581645Sjasone{
14681645Sjasone	int ret;
14781645Sjasone
14881645Sjasone	mtx_lock(&sema->sema_mtx);
14981645Sjasone
15081645Sjasone	if (sema->sema_value > 0) {
15181645Sjasone		/* Success. */
15281645Sjasone		sema->sema_value--;
15381645Sjasone		ret = 1;
15481645Sjasone
15581645Sjasone		CTR5(KTR_LOCK, __func__ "(%p) \"%s\" v = %d at %s:%d", sema,
15681645Sjasone		    cv_wmesg(&sema->sema_cv), sema->sema_value, file, line);
15781645Sjasone	} else {
15881645Sjasone		ret = 0;
15981645Sjasone
16081645Sjasone		CTR4(KTR_LOCK, __func__ "(%p) \"%s\" fail at %s:%d", sema,
16181645Sjasone		    cv_wmesg(&sema->sema_cv), file, line);
16281645Sjasone	}
16381645Sjasone
16481645Sjasone	mtx_unlock(&sema->sema_mtx);
16581645Sjasone	return (ret);
16681645Sjasone}
16781645Sjasone
16881645Sjasoneint
16981645Sjasonesema_value(struct sema *sema)
17081645Sjasone{
17181645Sjasone	int ret;
17281645Sjasone
17381645Sjasone	mtx_lock(&sema->sema_mtx);
17481645Sjasone	ret = sema->sema_value;
17581645Sjasone	mtx_unlock(&sema->sema_mtx);
17681645Sjasone	return (ret);
17781645Sjasone}
178