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 }