1 /* 2 * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * Copyright (c) 2013 iXsystems, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #ifndef _OPENSOLARIS_SYS_CONDVAR_H_ 31 #define _OPENSOLARIS_SYS_CONDVAR_H_ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 36 #include <sys/spl_condvar.h> 37 #include <sys/mutex.h> 38 #include <sys/time.h> 39 #include <sys/errno.h> 40 41 /* 42 * cv_timedwait() is similar to cv_wait() except that it additionally expects 43 * a timeout value specified in ticks. When woken by cv_signal() or 44 * cv_broadcast() it returns 1, otherwise when the timeout is reached -1 is 45 * returned. 46 * 47 * cv_timedwait_sig() behaves the same as cv_timedwait() but blocks 48 * interruptibly and can be woken by a signal (EINTR, ERESTART). When 49 * this occurs 0 is returned. 50 * 51 * cv_timedwait_io() and cv_timedwait_sig_io() are variants of cv_timedwait() 52 * and cv_timedwait_sig() which should be used when waiting for outstanding 53 * IO to complete. They are responsible for updating the iowait accounting 54 * when this is supported by the platform. 55 * 56 * cv_timedwait_hires() and cv_timedwait_sig_hires() are high resolution 57 * versions of cv_timedwait() and cv_timedwait_sig(). They expect the timeout 58 * to be specified as a hrtime_t allowing for timeouts of less than a tick. 59 * 60 * N.B. The return values differ slightly from the illumos implementation 61 * which returns the time remaining, instead of 1, when woken. They both 62 * return -1 on timeout. Consumers which need to know the time remaining 63 * are responsible for tracking it themselves. 64 */ 65 66 static __inline sbintime_t 67 zfs_nstosbt(int64_t _ns) 68 { 69 sbintime_t sb = 0; 70 71 #ifdef KASSERT 72 KASSERT(_ns >= 0, ("Negative values illegal for nstosbt: %jd", _ns)); 73 #endif 74 if (_ns >= SBT_1S) { 75 sb = (_ns / 1000000000) * SBT_1S; 76 _ns = _ns % 1000000000; 77 } 78 /* 9223372037 = ceil(2^63 / 1000000000) */ 79 sb += ((_ns * 9223372037ull) + 0x7fffffff) >> 31; 80 return (sb); 81 } 82 83 84 typedef struct cv kcondvar_t; 85 #define CALLOUT_FLAG_ABSOLUTE C_ABSOLUTE 86 87 typedef enum { 88 CV_DEFAULT, 89 CV_DRIVER 90 } kcv_type_t; 91 92 #define zfs_cv_init(cv, name, type, arg) do { \ 93 const char *_name; \ 94 ASSERT((type) == CV_DEFAULT); \ 95 for (_name = #cv; *_name != '\0'; _name++) { \ 96 if (*_name >= 'a' && *_name <= 'z') \ 97 break; \ 98 } \ 99 if (*_name == '\0') \ 100 _name = #cv; \ 101 cv_init((cv), _name); \ 102 } while (0) 103 #define cv_init(cv, name, type, arg) zfs_cv_init(cv, name, type, arg) 104 105 106 static inline int 107 cv_wait_sig(kcondvar_t *cvp, kmutex_t *mp) 108 { 109 110 return (_cv_wait_sig(cvp, &(mp)->lock_object) == 0); 111 } 112 113 static inline int 114 cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t timo) 115 { 116 int rc; 117 118 timo -= ddi_get_lbolt(); 119 if (timo <= 0) 120 return (-1); 121 rc = _cv_timedwait_sbt((cvp), &(mp)->lock_object, \ 122 tick_sbt * (timo), 0, C_HARDCLOCK); 123 if (rc == EWOULDBLOCK) 124 return (-1); 125 return (1); 126 } 127 128 static inline int 129 cv_timedwait_sig(kcondvar_t *cvp, kmutex_t *mp, clock_t timo) 130 { 131 int rc; 132 133 timo -= ddi_get_lbolt(); 134 if (timo <= 0) 135 return (-1); 136 rc = _cv_timedwait_sig_sbt(cvp, &(mp)->lock_object, \ 137 tick_sbt * (timo), 0, C_HARDCLOCK); 138 if (rc == EWOULDBLOCK) 139 return (-1); 140 if (rc == EINTR || rc == ERESTART) 141 return (0); 142 143 return (1); 144 } 145 146 #define cv_timedwait_io cv_timedwait 147 #define cv_timedwait_idle cv_timedwait 148 #define cv_timedwait_sig_io cv_timedwait_sig 149 #define cv_wait_io cv_wait 150 #define cv_wait_io_sig cv_wait_sig 151 #define cv_wait_idle cv_wait 152 #define cv_timedwait_io_hires cv_timedwait_hires 153 #define cv_timedwait_idle_hires cv_timedwait_hires 154 155 static inline int 156 cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res, 157 int flag) 158 { 159 hrtime_t hrtime; 160 int rc; 161 162 ASSERT(tim >= res); 163 164 hrtime = gethrtime(); 165 if (flag == 0) 166 tim += hrtime; 167 168 if (hrtime >= tim) 169 return (-1); 170 rc = cv_timedwait_sbt(cvp, mp, zfs_nstosbt(tim), 171 zfs_nstosbt(res), C_ABSOLUTE); 172 173 if (rc == EWOULDBLOCK) 174 return (-1); 175 176 KASSERT(rc == 0, ("unexpected rc value %d", rc)); 177 return (1); 178 } 179 180 static inline int 181 cv_timedwait_sig_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, 182 hrtime_t res, int flag) 183 { 184 sbintime_t sbt; 185 hrtime_t hrtime; 186 int rc; 187 188 ASSERT(tim >= res); 189 190 hrtime = gethrtime(); 191 if (flag == 0) 192 tim += hrtime; 193 194 if (hrtime >= tim) 195 return (-1); 196 197 sbt = zfs_nstosbt(tim); 198 rc = cv_timedwait_sig_sbt(cvp, mp, sbt, zfs_nstosbt(res), C_ABSOLUTE); 199 200 switch (rc) { 201 case EWOULDBLOCK: 202 return (-1); 203 case EINTR: 204 case ERESTART: 205 return (0); 206 default: 207 KASSERT(rc == 0, ("unexpected rc value %d", rc)); 208 return (1); 209 } 210 } 211 212 #endif /* _OPENSOLARIS_SYS_CONDVAR_H_ */ 213