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