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