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  */
15 
16 /*
17  * condvar(9f)
18  */
19 
20 /* This is the API we're emulating */
21 #include <sys/condvar.h>
22 
23 #include <sys/errno.h>
24 #include <sys/debug.h>
25 #include <sys/thread.h>
26 
27 /* avoiding synch.h */
28 int	_lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *);
29 int	_lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
30 int	_lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *);
31 int	_lwp_cond_signal(lwp_cond_t *);
32 int	_lwp_cond_broadcast(lwp_cond_t *);
33 
34 
35 extern clock_t ddi_get_lbolt(void);
36 extern void clock2ts(clock_t, timespec_t *);
37 
38 static int cv__wait(kcondvar_t *, kmutex_t *, int);
39 static clock_t cv__twait(kcondvar_t *, kmutex_t *, clock_t, int);
40 
41 static const lwp_cond_t  default_cv =
42 	{{{0, 0, 0, 0}, USYNC_THREAD, _COND_MAGIC}, 0};
43 
44 
45 /* ARGSUSED */
46 void
47 cv_init(kcondvar_t *cv, char *name, kcv_type_t typ, void *arg)
48 {
49 	*cv = default_cv;
50 }
51 
52 /* ARGSUSED */
53 void
54 cv_destroy(kcondvar_t *cv)
55 {
56 }
57 
58 void
59 cv_signal(kcondvar_t *cv)
60 {
61 	(void) _lwp_cond_signal(cv);
62 }
63 
64 void
65 cv_broadcast(kcondvar_t *cv)
66 {
67 	(void) _lwp_cond_broadcast(cv);
68 }
69 
70 void
71 cv_wait(kcondvar_t *cv, kmutex_t *mp)
72 {
73 	(void) cv__wait(cv, mp, 0);
74 }
75 
76 int
77 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
78 {
79 	return (cv__wait(cv, mp, 1));
80 }
81 
82 int
83 cv__wait(kcondvar_t *cv, kmutex_t *mp, int sigok)
84 {
85 	int err;
86 
87 top:
88 	ASSERT(mp->m_owner == _curthread());
89 	mp->m_owner = _KTHREAD_INVALID;
90 	err = _lwp_cond_wait(cv, &mp->m_lock);
91 	mp->m_owner = _curthread();
92 
93 	if (err == 0)
94 		return (1);
95 	if (err == EINTR) {
96 		if (sigok)
97 			return (0);
98 		goto top;
99 	}
100 	return (-1);
101 }
102 
103 clock_t
104 cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
105 {
106 	clock_t delta;
107 
108 	delta = abstime - ddi_get_lbolt();
109 	return (cv__twait(cv, mp, delta, 0));
110 }
111 
112 clock_t
113 cv_timedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
114 {
115 	clock_t delta;
116 
117 	delta = abstime - ddi_get_lbolt();
118 	return (cv__twait(cv, mp, delta, 1));
119 }
120 
121 clock_t
122 cv_reltimedwait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, time_res_t res)
123 {
124 	_NOTE(ARGUNUSED(res))
125 
126 	return (cv__twait(cv, mp, delta, 0));
127 }
128 
129 clock_t
130 cv_reltimedwait_sig(kcondvar_t *cv, kmutex_t *mp, clock_t delta,
131     time_res_t res)
132 {
133 	_NOTE(ARGUNUSED(res))
134 
135 	return (cv__twait(cv, mp, delta, 1));
136 }
137 
138 /*
139  * Factored out implementation of all the cv_*timedwait* functions.
140  * Note that the delta passed in is relative to the (simulated)
141  * current time reported by ddi_get_lbolt().  Convert that to
142  * timespec format and keep calling _lwp_cond_reltimedwait,
143  * which (NB!) decrements that delta in-place!
144  */
145 static clock_t
146 cv__twait(kcondvar_t *cv, kmutex_t *mp, clock_t delta, int sigok)
147 {
148 	timestruc_t ts;
149 	int err;
150 
151 	if (delta <= 0)
152 		return (-1);
153 
154 	clock2ts(delta, &ts);
155 
156 top:
157 	if (ts.tv_sec == 0 && ts.tv_nsec == 0)
158 		return (-1);
159 
160 	ASSERT(mp->m_owner == _curthread());
161 	mp->m_owner = _KTHREAD_INVALID;
162 	err = _lwp_cond_reltimedwait(cv, &mp->m_lock, &ts);
163 	mp->m_owner = _curthread();
164 
165 	switch (err) {
166 	case 0:
167 		return (1);
168 	case EINTR:
169 		if (sigok)
170 			return (0);
171 		goto top;
172 	default:
173 		ASSERT(0);
174 		/* FALLTHROUGH */
175 	case ETIME:
176 		break;
177 	}
178 
179 	return (-1);
180 }
181