FreeBSD kernel kern code
kern_sema.c
Go to the documentation of this file.
1 /*-
2  * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
14  *
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
25  * DAMAGE.
26  */
27 
28 /*
29  * Counting semaphores.
30  *
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.
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$BSDSUniX$");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/ktr.h>
42 #include <sys/condvar.h>
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/sema.h>
46 
47 void
48 sema_init(struct sema *sema, int value, const char *description)
49 {
50 
51  KASSERT((value >= 0), ("%s(): negative value\n", __func__));
52 
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;
58 
59  CTR4(KTR_LOCK, "%s(%p, %d, \"%s\")", __func__, sema, value, description);
60 }
61 
62 void
64 {
65 
66  CTR3(KTR_LOCK, "%s(%p) \"%s\"", __func__, sema,
67  cv_wmesg(&sema->sema_cv));
68 
69  KASSERT((sema->sema_waiters == 0), ("%s(): waiters\n", __func__));
70 
71  mtx_destroy(&sema->sema_mtx);
72  cv_destroy(&sema->sema_cv);
73 }
74 
75 void
76 _sema_post(struct sema *sema, const char *file, int line)
77 {
78 
79  mtx_lock(&sema->sema_mtx);
80  sema->sema_value++;
81  if (sema->sema_waiters && sema->sema_value > 0)
82  cv_signal(&sema->sema_cv);
83 
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);
86 
87  mtx_unlock(&sema->sema_mtx);
88 }
89 
90 void
91 _sema_wait(struct sema *sema, const char *file, int line)
92 {
93 
94  mtx_lock(&sema->sema_mtx);
95  while (sema->sema_value == 0) {
96  sema->sema_waiters++;
97  cv_wait(&sema->sema_cv, &sema->sema_mtx);
98  sema->sema_waiters--;
99  }
100  sema->sema_value--;
101 
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);
104 
105  mtx_unlock(&sema->sema_mtx);
106 }
107 
108 int
109 _sema_timedwait(struct sema *sema, int timo, const char *file, int line)
110 {
111  int error;
112 
113  mtx_lock(&sema->sema_mtx);
114 
115  /*
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
119  * long to wait.
120  */
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--;
125  }
126  if (sema->sema_value > 0) {
127  /* Success. */
128  sema->sema_value--;
129  error = 0;
130 
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);
133  } else {
134  CTR5(KTR_LOCK, "%s(%p) \"%s\" fail at %s:%d", __func__, sema,
135  cv_wmesg(&sema->sema_cv), file, line);
136  }
137 
138  mtx_unlock(&sema->sema_mtx);
139  return (error);
140 }
141 
142 int
143 _sema_trywait(struct sema *sema, const char *file, int line)
144 {
145  int ret;
146 
147  mtx_lock(&sema->sema_mtx);
148 
149  if (sema->sema_value > 0) {
150  /* Success. */
151  sema->sema_value--;
152  ret = 1;
153 
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);
156  } else {
157  ret = 0;
158 
159  CTR5(KTR_LOCK, "%s(%p) \"%s\" fail at %s:%d", __func__, sema,
160  cv_wmesg(&sema->sema_cv), file, line);
161  }
162 
163  mtx_unlock(&sema->sema_mtx);
164  return (ret);
165 }
166 
167 int
169 {
170  int ret;
171 
172  mtx_lock(&sema->sema_mtx);
173  ret = sema->sema_value;
174  mtx_unlock(&sema->sema_mtx);
175  return (ret);
176 }
int sema_value(struct sema *sema)
Definition: kern_sema.c:168
caddr_t value
Definition: linker_if.m:51
void cv_destroy(struct cv *cvp)
Definition: kern_condvar.c:75
void cv_signal(struct cv *cvp)
Definition: kern_condvar.c:414
void _sema_wait(struct sema *sema, const char *file, int line)
Definition: kern_sema.c:91
int _sema_trywait(struct sema *sema, const char *file, int line)
Definition: kern_sema.c:143
static struct semid_kernel * sema
Definition: sysv_sem.c:100
void cv_init(struct cv *cvp, const char *desc)
Definition: kern_condvar.c:63
int _sema_timedwait(struct sema *sema, int timo, const char *file, int line)
Definition: kern_sema.c:109
__FBSDID("$BSDSUniX$")
void mtx_init(struct mtx *m, const char *name, const char *type, int opts)
Definition: kern_mutex.c:837
void sema_init(struct sema *sema, int value, const char *description)
Definition: kern_sema.c:48
void mtx_destroy(struct mtx *m)
Definition: kern_mutex.c:884
void _sema_post(struct sema *sema, const char *file, int line)
Definition: kern_sema.c:76
void sema_destroy(struct sema *sema)
Definition: kern_sema.c:63