2 * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice(s), this list of conditions and the following disclaimer as
9 * the first lines of this file unmodified other than the possible
10 * addition of one or more copyright notices.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice(s), this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 * Counting semaphores.
31 * Priority propagation will not generally raise the priority of semaphore
32 * "owners" (a misnomer in the context of semaphores), so should not be relied
33 * upon in combination with semaphores.
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/condvar.h>
44 #include <sys/mutex.h>
48 sema_init(struct sema
*sema
, int value
, const char *description
)
51 KASSERT((value
>= 0), ("%s(): negative value\n", __func__
));
53 bzero(sema
, sizeof(*sema
));
54 mtx_init(&sema
->sema_mtx
, description
, "sema backing lock",
55 MTX_DEF
| MTX_NOWITNESS
| MTX_QUIET
);
56 cv_init(&sema
->sema_cv
, description
);
57 sema
->sema_value
= value
;
59 CTR4(KTR_LOCK
, "%s(%p, %d, \"%s\")", __func__
, sema
, value
, description
);
63 sema_destroy(struct sema
*sema
)
66 CTR3(KTR_LOCK
, "%s(%p) \"%s\"", __func__
, sema
,
67 cv_wmesg(&sema
->sema_cv
));
69 KASSERT((sema
->sema_waiters
== 0), ("%s(): waiters\n", __func__
));
71 mtx_destroy(&sema
->sema_mtx
);
72 cv_destroy(&sema
->sema_cv
);
76 _sema_post(struct sema
*sema
, const char *file
, int line
)
79 mtx_lock(&sema
->sema_mtx
);
81 if (sema
->sema_waiters
&& sema
->sema_value
> 0)
82 cv_signal(&sema
->sema_cv
);
84 CTR6(KTR_LOCK
, "%s(%p) \"%s\" v = %d at %s:%d", __func__
, sema
,
85 cv_wmesg(&sema
->sema_cv
), sema
->sema_value
, file
, line
);
87 mtx_unlock(&sema
->sema_mtx
);
91 _sema_wait(struct sema
*sema
, const char *file
, int line
)
94 mtx_lock(&sema
->sema_mtx
);
95 while (sema
->sema_value
== 0) {
97 cv_wait(&sema
->sema_cv
, &sema
->sema_mtx
);
102 CTR6(KTR_LOCK
, "%s(%p) \"%s\" v = %d at %s:%d", __func__
, sema
,
103 cv_wmesg(&sema
->sema_cv
), sema
->sema_value
, file
, line
);
105 mtx_unlock(&sema
->sema_mtx
);
109 _sema_timedwait(struct sema
*sema
, int timo
, const char *file
, int line
)
113 mtx_lock(&sema
->sema_mtx
);
116 * A spurious wakeup will cause the timeout interval to start over.
117 * This isn't a big deal as long as spurious wakeups don't occur
118 * continuously, since the timeout period is merely a lower bound on how
121 for (error
= 0; sema
->sema_value
== 0 && error
== 0;) {
122 sema
->sema_waiters
++;
123 error
= cv_timedwait(&sema
->sema_cv
, &sema
->sema_mtx
, timo
);
124 sema
->sema_waiters
--;
126 if (sema
->sema_value
> 0) {
131 CTR6(KTR_LOCK
, "%s(%p) \"%s\" v = %d at %s:%d", __func__
, sema
,
132 cv_wmesg(&sema
->sema_cv
), sema
->sema_value
, file
, line
);
134 CTR5(KTR_LOCK
, "%s(%p) \"%s\" fail at %s:%d", __func__
, sema
,
135 cv_wmesg(&sema
->sema_cv
), file
, line
);
138 mtx_unlock(&sema
->sema_mtx
);
143 _sema_trywait(struct sema
*sema
, const char *file
, int line
)
147 mtx_lock(&sema
->sema_mtx
);
149 if (sema
->sema_value
> 0) {
154 CTR6(KTR_LOCK
, "%s(%p) \"%s\" v = %d at %s:%d", __func__
, sema
,
155 cv_wmesg(&sema
->sema_cv
), sema
->sema_value
, file
, line
);
159 CTR5(KTR_LOCK
, "%s(%p) \"%s\" fail at %s:%d", __func__
, sema
,
160 cv_wmesg(&sema
->sema_cv
), file
, line
);
163 mtx_unlock(&sema
->sema_mtx
);
168 sema_value(struct sema
*sema
)
172 mtx_lock(&sema
->sema_mtx
);
173 ret
= sema
->sema_value
;
174 mtx_unlock(&sema
->sema_mtx
);