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 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 56 cv_destroy(kcondvar_t *cv) 57 { 58 } 59 60 void 61 cv_signal(kcondvar_t *cv) 62 { 63 (void) _lwp_cond_signal(cv); 64 } 65 66 void 67 cv_broadcast(kcondvar_t *cv) 68 { 69 (void) _lwp_cond_broadcast(cv); 70 } 71 72 void 73 cv_wait(kcondvar_t *cv, kmutex_t *mp) 74 { 75 (void) cv__wait(cv, mp, 0); 76 } 77 78 int 79 cv_wait_sig(kcondvar_t *cv, kmutex_t *mp) 80 { 81 return (cv__wait(cv, mp, 1)); 82 } 83 84 int 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 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 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 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 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 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 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 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