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
cv_init(kcondvar_t * cv,char * name,kcv_type_t typ,void * arg)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
cv_destroy(kcondvar_t * cv)54 cv_destroy(kcondvar_t *cv)
55 {
56 }
57
58 void
cv_signal(kcondvar_t * cv)59 cv_signal(kcondvar_t *cv)
60 {
61 (void) _lwp_cond_signal(cv);
62 }
63
64 void
cv_broadcast(kcondvar_t * cv)65 cv_broadcast(kcondvar_t *cv)
66 {
67 (void) _lwp_cond_broadcast(cv);
68 }
69
70 void
cv_wait(kcondvar_t * cv,kmutex_t * mp)71 cv_wait(kcondvar_t *cv, kmutex_t *mp)
72 {
73 (void) cv__wait(cv, mp, 0);
74 }
75
76 int
cv_wait_sig(kcondvar_t * cv,kmutex_t * mp)77 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp)
78 {
79 return (cv__wait(cv, mp, 1));
80 }
81
82 int
cv__wait(kcondvar_t * cv,kmutex_t * mp,int sigok)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
cv_timedwait(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)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
cv_timedwait_sig(kcondvar_t * cv,kmutex_t * mp,clock_t abstime)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
cv_reltimedwait(kcondvar_t * cv,kmutex_t * mp,clock_t delta,time_res_t res)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
cv_reltimedwait_sig(kcondvar_t * cv,kmutex_t * mp,clock_t delta,time_res_t res)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
cv__twait(kcondvar_t * cv,kmutex_t * mp,clock_t delta,int sigok)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