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 #include <sys/systm.h> 28 29 /* avoiding synch.h */ 30 int _lwp_cond_wait(lwp_cond_t *, lwp_mutex_t *); 31 int _lwp_cond_timedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *); 32 int _lwp_cond_reltimedwait(lwp_cond_t *, lwp_mutex_t *, timespec_t *); 33 int _lwp_cond_signal(lwp_cond_t *); 34 int _lwp_cond_broadcast(lwp_cond_t *); 35 36 37 extern clock_t ddi_get_lbolt(void); 38 39 static int cv__wait(kcondvar_t *, kmutex_t *, int); 40 static clock_t cv__twait(kcondvar_t *, kmutex_t *, clock_t, int, 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, 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, 0)); 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, 1)); 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, 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, 0)); 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, int hires) 161 { 162 timestruc_t ts; 163 int err; 164 165 if (delta <= 0) 166 return (-1); 167 168 if (hires) { 169 ts.tv_sec = delta / NANOSEC; 170 ts.tv_nsec = delta % NANOSEC; 171 } else { 172 ts.tv_sec = delta / hz; 173 ts.tv_nsec = (delta % hz) * (NANOSEC / hz); 174 } 175 176 top: 177 if (ts.tv_sec == 0 && ts.tv_nsec == 0) 178 return (-1); 179 180 ASSERT(mp->m_owner == _curthread()); 181 mp->m_owner = _KTHREAD_INVALID; 182 err = _lwp_cond_reltimedwait(cv, &mp->m_lock, &ts); 183 mp->m_owner = _curthread(); 184 185 switch (err) { 186 case 0: 187 return (1); 188 case EINTR: 189 if (sigok) 190 return (0); 191 goto top; 192 default: 193 ASSERT(0); 194 /* FALLTHROUGH */ 195 case ETIME: 196 break; 197 } 198 199 return (-1); 200 } 201