1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
14 * Copyright 2017 RackTop Systems.
15 * Copyright 2019 Joyent, Inc.
16 */
17
18 /*
19 * condvar(9f)
20 */
21
22 /* This is the API we're emulating */
23 #include <sys/condvar.h>
24
25 #include <sys/errno.h>
26 #include <sys/debug.h>
27 #include <sys/thread.h>
28 #include <sys/systm.h>
29
30 /* avoiding synch.h */
31 int _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
32 int _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
33 int _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
34 int _lwp_cond_signal(lwp_cond_t *);
35 int _lwp_cond_broadcast(lwp_cond_t *);
36
37
38 extern clock_t ddi_get_lbolt(void);
39
40 static int cv__wait(kcondvar_t *, kmutex_t *, int);
41 static clock_t cv__twait(kcondvar_t *, kmutex_t *, clock_t, int, int);
42
43 static const lwp_cond_t default_cv =
44 {{{0, 0, 0, 0}, USYNC_THREAD, _COND_MAGIC}, 0};
45
46
47 /* ARGSUSED */
48 void
cv_init(kcondvar_t * cv,char * name,kcv_type_t typ,void * arg)49 cv_init(kcondvar_t *cv, char *name, kcv_type_t typ, void *arg)
50 {
51 *cv = default_cv;
52 }
53
54 /* ARGSUSED */
55 void
cv_destroy(kcondvar_t * cv)56 cv_destroy(kcondvar_t *cv)
57 {
58 }
59
60 void
cv_signal(kcondvar_t * cv)61 cv_signal(kcondvar_t *cv)
62 {
63 (void) _lwp_cond_signal(cv);
64 }
65
66 void
cv_broadcast(kcondvar_t * cv)67 cv_broadcast(kcondvar_t *cv)
68 {
69 (void) _lwp_cond_broadcast(cv);
70 }
71
72 void
cv_wait(kcondvar_t * cv,kmutex_t * mp)73 cv_wait(kcondvar_t *cv, kmutex_t *mp)
74 {
75 (void) cv__wait(cv, mp, 0);
76 }
77
78 int
cv_wait_sig(kcondvar_t * cv,kmutex_t * mp)79 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
80 {
81 return (cv__wait(cv, mp, 1));
82 }
83
84 int
cv__wait(kcondvar_t * cv,kmutex_t * mp,int sigok)85 cv__wait(kcondvar_t *cv, kmutex_t *mp, int sigok)
86 {
87 int err;
88
89 top:
90 ASSERT(mp->m_owner == _curthread());
91 mp->m_owner = _KTHREAD_INVALID;
92 err = _lwp_cond_wait(cv, &mp->m_lock);
93 mp->m_owner = _curthread();
94
95 if (err == 0)
96 return (1);
97 if (err == EINTR) {
98 if (sigok)
99 return (0);
100 goto top;
101 }
102 return (-1);
103 }
104
105 clock_t
cv_timedwait(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)106 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
107 {
108 clock_t delta;
109
110 delta = abstime - ddi_get_lbolt();
111 return (cv__twait(cv, mp, delta, 0, 0));
112 }
113
114 clock_t
cv_timedwait_sig(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)115 cv_timedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
116 {
117 clock_t delta;
118
119 delta = abstime - ddi_get_lbolt();
120 return (cv__twait(cv, mp, delta, 1, 0));
121 }
122
123 int
cv_timedwait_sig_hrtime(kcondvar_t * cv,kmutex_t * mp,hrtime_t tim)124 cv_timedwait_sig_hrtime(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim)
125 {
126 clock_t delta;
127
128 delta = tim;
129 return (cv__twait(cv, mp, delta, 1, 1));
130 }
131
132 /*ARGSUSED*/
133 clock_t
cv_timedwait_hires(kcondvar_t * cv,kmutex_t * mp,hrtime_t tim,hrtime_t res,int flag)134 cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
135 int flag)
136 {
137 clock_t delta;
138
139 delta = tim;
140 if (flag & CALLOUT_FLAG_ABSOLUTE)
141 delta -= gethrtime();
142 return (cv__twait(cv, mp, delta, 0, 1));
143 }
144
145 clock_t
cv_reltimedwait(kcondvar_t * cv,kmutex_t * mp,clock_t delta,time_res_t res)146 cv_reltimedwait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, time_res_t res)
147 {
148 _NOTE(ARGUNUSED(res))
149
150 return (cv__twait(cv, mp, delta, 0, 0));
151 }
152
153 clock_t
cv_reltimedwait_sig(kcondvar_t * cv,kmutex_t * mp,clock_t delta,time_res_t res)154 cv_reltimedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t delta,
155 time_res_t res)
156 {
157 _NOTE(ARGUNUSED(res))
158
159 return (cv__twait(cv, mp, delta, 1, 0));
160 }
161
162 /*
163 * Factored out implementation of all the cv_*timedwait* functions.
164 * Note that the delta passed in is relative to the (simulated)
165 * current time reported by ddi_get_lbolt(). Convert that to
166 * timespec format and keep calling _lwp_cond_reltimedwait,
167 * which (NB!) decrements that delta in-place!
168 */
169 static clock_t
cv__twait(kcondvar_t * cv,kmutex_t * mp,clock_t delta,int sigok,int hires)170 cv__twait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, int sigok, int hires)
171 {
172 timestruc_t ts;
173 int err;
174
175 if (delta <= 0)
176 return (-1);
177
178 if (hires) {
179 ts.tv_sec = delta / NANOSEC;
180 ts.tv_nsec = delta % NANOSEC;
181 } else {
182 ts.tv_sec = delta / hz;
183 ts.tv_nsec = (delta % hz) * (NANOSEC / hz);
184 }
185
186 top:
187 if (ts.tv_sec == 0 && ts.tv_nsec == 0)
188 return (-1);
189
190 ASSERT(mp->m_owner == _curthread());
191 mp->m_owner = _KTHREAD_INVALID;
192 err = _lwp_cond_reltimedwait(cv, &mp->m_lock, &ts);
193 mp->m_owner = _curthread();
194
195 switch (err) {
196 case 0:
197 return (1);
198 case EINTR:
199 if (sigok)
200 return (0);
201 goto top;
202 default:
203 ASSERT(0);
204 /* FALLTHROUGH */
205 case ETIME:
206 break;
207 }
208
209 return (-1);
210 }
211