1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 30*7c478bd9Sstevel@tonic-gate #include <signal.h> 31*7c478bd9Sstevel@tonic-gate #include <limits.h> 32*7c478bd9Sstevel@tonic-gate #include <time.h> 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <fmd_time.h> 35*7c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 36*7c478bd9Sstevel@tonic-gate #include <fmd_error.h> 37*7c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 38*7c478bd9Sstevel@tonic-gate #include <fmd.h> 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate void 41*7c478bd9Sstevel@tonic-gate fmd_time_gettimeofday(struct timeval *tvp) 42*7c478bd9Sstevel@tonic-gate { 43*7c478bd9Sstevel@tonic-gate if (fmd.d_clockops->fto_gettimeofday(tvp, NULL) != 0) 44*7c478bd9Sstevel@tonic-gate fmd_panic("failed to read time-of-day clock"); 45*7c478bd9Sstevel@tonic-gate } 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate hrtime_t 48*7c478bd9Sstevel@tonic-gate fmd_time_gethrtime(void) 49*7c478bd9Sstevel@tonic-gate { 50*7c478bd9Sstevel@tonic-gate return (fmd.d_clockops->fto_gethrtime()); 51*7c478bd9Sstevel@tonic-gate } 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate void 54*7c478bd9Sstevel@tonic-gate fmd_time_addhrtime(hrtime_t delta) 55*7c478bd9Sstevel@tonic-gate { 56*7c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_addhrtime(delta); 57*7c478bd9Sstevel@tonic-gate } 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate void 60*7c478bd9Sstevel@tonic-gate fmd_time_waithrtime(hrtime_t delta) 61*7c478bd9Sstevel@tonic-gate { 62*7c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_waithrtime(delta); 63*7c478bd9Sstevel@tonic-gate } 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate void 66*7c478bd9Sstevel@tonic-gate fmd_time_waitcancel(pthread_t tid) 67*7c478bd9Sstevel@tonic-gate { 68*7c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_waitcancel(tid); 69*7c478bd9Sstevel@tonic-gate } 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* 72*7c478bd9Sstevel@tonic-gate * To synchronize TOD with a gethrtime() source, we repeatedly sample TOD in 73*7c478bd9Sstevel@tonic-gate * between two calls to gethrtime(), which places a reasonably tight bound on 74*7c478bd9Sstevel@tonic-gate * the high-resolution time that matches the TOD value we sampled. We repeat 75*7c478bd9Sstevel@tonic-gate * this process several times and ultimately select the sample where the two 76*7c478bd9Sstevel@tonic-gate * values of gethrtime() were closest. We then assign the average of those 77*7c478bd9Sstevel@tonic-gate * two high-resolution times to be the gethrtime() associated with that TOD. 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate void 80*7c478bd9Sstevel@tonic-gate fmd_time_sync(fmd_timeval_t *ftv, hrtime_t *hrp, uint_t samples) 81*7c478bd9Sstevel@tonic-gate { 82*7c478bd9Sstevel@tonic-gate const fmd_timeops_t *ftop = fmd.d_clockops; 83*7c478bd9Sstevel@tonic-gate hrtime_t hrtbase, hrtmin = INT64_MAX; 84*7c478bd9Sstevel@tonic-gate struct timeval todbase; 85*7c478bd9Sstevel@tonic-gate uint_t i; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate for (i = 0; i < samples; i++) { 88*7c478bd9Sstevel@tonic-gate hrtime_t t0, t1, delta; 89*7c478bd9Sstevel@tonic-gate struct timeval tod; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate t0 = ftop->fto_gethrtime(); 92*7c478bd9Sstevel@tonic-gate (void) ftop->fto_gettimeofday(&tod, NULL); 93*7c478bd9Sstevel@tonic-gate t1 = ftop->fto_gethrtime(); 94*7c478bd9Sstevel@tonic-gate delta = t1 - t0; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate if (delta < hrtmin) { 97*7c478bd9Sstevel@tonic-gate hrtmin = delta; 98*7c478bd9Sstevel@tonic-gate hrtbase = t0 + delta / 2; 99*7c478bd9Sstevel@tonic-gate todbase = tod; 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate } 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate if (ftv != NULL) { 104*7c478bd9Sstevel@tonic-gate ftv->ftv_sec = todbase.tv_sec; 105*7c478bd9Sstevel@tonic-gate ftv->ftv_nsec = todbase.tv_usec * (NANOSEC / MICROSEC); 106*7c478bd9Sstevel@tonic-gate } 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate if (hrp != NULL) 109*7c478bd9Sstevel@tonic-gate *hrp = hrtbase; 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * Convert a high-resolution timestamp into 64-bit seconds and nanoseconds. 114*7c478bd9Sstevel@tonic-gate * For efficiency, the multiplication and division are expanded using the 115*7c478bd9Sstevel@tonic-gate * clever algorithm originally designed for the kernel in hrt2ts(). Refer to 116*7c478bd9Sstevel@tonic-gate * the comments in uts/common/os/timers.c for an explanation of how it works. 117*7c478bd9Sstevel@tonic-gate */ 118*7c478bd9Sstevel@tonic-gate static void 119*7c478bd9Sstevel@tonic-gate fmd_time_hrt2ftv(hrtime_t hrt, fmd_timeval_t *ftv) 120*7c478bd9Sstevel@tonic-gate { 121*7c478bd9Sstevel@tonic-gate uint32_t sec, nsec, tmp; 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate tmp = (uint32_t)(hrt >> 30); 124*7c478bd9Sstevel@tonic-gate sec = tmp - (tmp >> 2); 125*7c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 5); 126*7c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 1); 127*7c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 6) + 7; 128*7c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 3); 129*7c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 1); 130*7c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 3); 131*7c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 4); 132*7c478bd9Sstevel@tonic-gate tmp = (sec << 7) - sec - sec - sec; 133*7c478bd9Sstevel@tonic-gate tmp = (tmp << 7) - tmp - tmp - tmp; 134*7c478bd9Sstevel@tonic-gate tmp = (tmp << 7) - tmp - tmp - tmp; 135*7c478bd9Sstevel@tonic-gate nsec = (uint32_t)hrt - (tmp << 9); 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate while (nsec >= NANOSEC) { 138*7c478bd9Sstevel@tonic-gate nsec -= NANOSEC; 139*7c478bd9Sstevel@tonic-gate sec++; 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate ftv->ftv_sec = sec; 143*7c478bd9Sstevel@tonic-gate ftv->ftv_nsec = nsec; 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* 147*7c478bd9Sstevel@tonic-gate * Convert a high-resolution time from gethrtime() to a TOD (fmd_timeval_t). 148*7c478bd9Sstevel@tonic-gate * We convert 'tod_base' to nanoseconds, adjust it based on the difference 149*7c478bd9Sstevel@tonic-gate * between the corresponding 'hrt_base' and the event high-res time 'hrt', 150*7c478bd9Sstevel@tonic-gate * and then repack the result into ftv_sec and ftv_nsec for our output. 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate void 153*7c478bd9Sstevel@tonic-gate fmd_time_hrt2tod(hrtime_t hrt_base, const fmd_timeval_t *tod_base, 154*7c478bd9Sstevel@tonic-gate hrtime_t hrt, fmd_timeval_t *ftv) 155*7c478bd9Sstevel@tonic-gate { 156*7c478bd9Sstevel@tonic-gate fmd_time_hrt2ftv(tod_base->ftv_sec * NANOSEC + 157*7c478bd9Sstevel@tonic-gate tod_base->ftv_nsec + (hrt - hrt_base), ftv); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* 161*7c478bd9Sstevel@tonic-gate * Convert a TOD (fmd_timeval_t) to a high-resolution time from gethrtime(). 162*7c478bd9Sstevel@tonic-gate * Note that since TOD occurred in the past, the resulting value may be a 163*7c478bd9Sstevel@tonic-gate * negative number according the current gethrtime() clock value. 164*7c478bd9Sstevel@tonic-gate */ 165*7c478bd9Sstevel@tonic-gate void 166*7c478bd9Sstevel@tonic-gate fmd_time_tod2hrt(hrtime_t hrt_base, const fmd_timeval_t *tod_base, 167*7c478bd9Sstevel@tonic-gate const fmd_timeval_t *ftv, hrtime_t *hrtp) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate hrtime_t tod_hrt = tod_base->ftv_sec * NANOSEC + tod_base->ftv_nsec; 170*7c478bd9Sstevel@tonic-gate hrtime_t ftv_hrt = ftv->ftv_sec * NANOSEC + ftv->ftv_nsec; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate *hrtp = hrt_base - (tod_hrt - ftv_hrt); 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* 176*7c478bd9Sstevel@tonic-gate * Adjust a high-resolution time based on the low bits of time stored in ENA. 177*7c478bd9Sstevel@tonic-gate * The assumption here in that ENA won't wrap between the time it is computed 178*7c478bd9Sstevel@tonic-gate * and the time the error is queued (when we capture a full 64-bits of hrtime). 179*7c478bd9Sstevel@tonic-gate * We extract the relevant ENA time bits as 't0' and subtract the difference 180*7c478bd9Sstevel@tonic-gate * between these bits and the corresponding low bits of 'hrt' from 'hrt'. 181*7c478bd9Sstevel@tonic-gate */ 182*7c478bd9Sstevel@tonic-gate hrtime_t 183*7c478bd9Sstevel@tonic-gate fmd_time_ena2hrt(hrtime_t hrt, uint64_t ena) 184*7c478bd9Sstevel@tonic-gate { 185*7c478bd9Sstevel@tonic-gate hrtime_t t0, mask; 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate switch (ENA_FORMAT(ena)) { 188*7c478bd9Sstevel@tonic-gate case FM_ENA_FMT1: 189*7c478bd9Sstevel@tonic-gate t0 = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT; 190*7c478bd9Sstevel@tonic-gate mask = ENA_FMT1_TIME_MASK >> ENA_FMT1_TIME_SHFT; 191*7c478bd9Sstevel@tonic-gate hrt -= (hrt - t0) & mask; 192*7c478bd9Sstevel@tonic-gate break; 193*7c478bd9Sstevel@tonic-gate case FM_ENA_FMT2: 194*7c478bd9Sstevel@tonic-gate t0 = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT; 195*7c478bd9Sstevel@tonic-gate mask = ENA_FMT2_TIME_MASK >> ENA_FMT2_TIME_SHFT; 196*7c478bd9Sstevel@tonic-gate hrt -= (hrt - t0) & mask; 197*7c478bd9Sstevel@tonic-gate break; 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate return (hrt); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * To implement a simulated clock, we keep track of an hrtime_t value which 205*7c478bd9Sstevel@tonic-gate * starts at zero and is incremented only by fmd_time_addhrtime() (i.e. when 206*7c478bd9Sstevel@tonic-gate * the driver of the simulation requests that the clock advance). We sample 207*7c478bd9Sstevel@tonic-gate * the native time-of-day clock once at the start of the simulation and then 208*7c478bd9Sstevel@tonic-gate * return subsequent time-of-day values by adjusting TOD using the hrtime_t 209*7c478bd9Sstevel@tonic-gate * clock setting. Simulated nanosleep (fmd_time_waithrtime() entry point) is 210*7c478bd9Sstevel@tonic-gate * implemented by waiting on fts->fts_cv for the hrtime_t to increment. 211*7c478bd9Sstevel@tonic-gate */ 212*7c478bd9Sstevel@tonic-gate static void * 213*7c478bd9Sstevel@tonic-gate fmd_simulator_init(void) 214*7c478bd9Sstevel@tonic-gate { 215*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd_alloc(sizeof (fmd_timesim_t), FMD_SLEEP); 216*7c478bd9Sstevel@tonic-gate struct timeval tv; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&fts->fts_lock, NULL); 219*7c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&fts->fts_cv, NULL); 220*7c478bd9Sstevel@tonic-gate (void) gettimeofday(&tv, NULL); 221*7c478bd9Sstevel@tonic-gate 222*7c478bd9Sstevel@tonic-gate fts->fts_tod = (hrtime_t)tv.tv_sec * NANOSEC + 223*7c478bd9Sstevel@tonic-gate (hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC); 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate fts->fts_hrt = 0; 226*7c478bd9Sstevel@tonic-gate fts->fts_cancel = 0; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_TMR, "simulator tod base tv_sec=%lx hrt=%llx\n", 229*7c478bd9Sstevel@tonic-gate tv.tv_sec, fts->fts_tod); 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate return (fts); 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate static void 235*7c478bd9Sstevel@tonic-gate fmd_simulator_fini(void *fts) 236*7c478bd9Sstevel@tonic-gate { 237*7c478bd9Sstevel@tonic-gate if (fts != NULL) 238*7c478bd9Sstevel@tonic-gate fmd_free(fts, sizeof (fmd_timesim_t)); 239*7c478bd9Sstevel@tonic-gate } 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 242*7c478bd9Sstevel@tonic-gate static int 243*7c478bd9Sstevel@tonic-gate fmd_simulator_tod(struct timeval *tvp, void *tzp) 244*7c478bd9Sstevel@tonic-gate { 245*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 246*7c478bd9Sstevel@tonic-gate hrtime_t tod, hrt, sec, rem; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate tod = fts->fts_tod; 251*7c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate sec = tod / NANOSEC + hrt / NANOSEC; 256*7c478bd9Sstevel@tonic-gate rem = tod % NANOSEC + hrt % NANOSEC; 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate tvp->tv_sec = sec + rem / NANOSEC; 259*7c478bd9Sstevel@tonic-gate tvp->tv_usec = (rem % NANOSEC) / (NANOSEC / MICROSEC); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate return (0); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate static hrtime_t 265*7c478bd9Sstevel@tonic-gate fmd_simulator_hrt(void) 266*7c478bd9Sstevel@tonic-gate { 267*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 268*7c478bd9Sstevel@tonic-gate hrtime_t hrt; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 271*7c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt; 272*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate return (hrt); 275*7c478bd9Sstevel@tonic-gate } 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate static void 278*7c478bd9Sstevel@tonic-gate fmd_simulator_add(hrtime_t delta) 279*7c478bd9Sstevel@tonic-gate { 280*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate if (fts->fts_hrt + delta < fts->fts_hrt) 285*7c478bd9Sstevel@tonic-gate fts->fts_hrt = INT64_MAX; /* do not increment past apocalypse */ 286*7c478bd9Sstevel@tonic-gate else 287*7c478bd9Sstevel@tonic-gate fts->fts_hrt += delta; 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_TMR, "hrt clock set %llx", fts->fts_hrt)); 290*7c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_TMR, "hrt clock set %llx\n", fts->fts_hrt); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 293*7c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&fts->fts_cv); 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate static void 297*7c478bd9Sstevel@tonic-gate fmd_simulator_wait(hrtime_t delta) 298*7c478bd9Sstevel@tonic-gate { 299*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 300*7c478bd9Sstevel@tonic-gate uint64_t hrt; 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * If the delta causes time to wrap because we've reached the simulated 306*7c478bd9Sstevel@tonic-gate * apocalypse, then wait forever. We make 'hrt' unsigned so that the 307*7c478bd9Sstevel@tonic-gate * while-loop comparison fts_hrt < UINT64_MAX will always return true. 308*7c478bd9Sstevel@tonic-gate */ 309*7c478bd9Sstevel@tonic-gate if (fts->fts_hrt + delta < fts->fts_hrt) 310*7c478bd9Sstevel@tonic-gate hrt = UINT64_MAX; 311*7c478bd9Sstevel@tonic-gate else 312*7c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt + delta; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate while (fts->fts_hrt < hrt && fts->fts_cancel == 0) 315*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&fts->fts_cv, &fts->fts_lock); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate if (fts->fts_cancel != 0) 318*7c478bd9Sstevel@tonic-gate fts->fts_cancel--; /* cancel has been processed */ 319*7c478bd9Sstevel@tonic-gate 320*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 324*7c478bd9Sstevel@tonic-gate static void 325*7c478bd9Sstevel@tonic-gate fmd_simulator_cancel(pthread_t tid) 326*7c478bd9Sstevel@tonic-gate { 327*7c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 330*7c478bd9Sstevel@tonic-gate fts->fts_cancel++; 331*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 332*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&fts->fts_cv); 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * Native time is implemented by calls to gethrtime() and gettimeofday(), which 337*7c478bd9Sstevel@tonic-gate * are stored directly in the native time ops-vector defined below. To wait on 338*7c478bd9Sstevel@tonic-gate * the native clock we use nanosleep(), which we can abort using a signal. The 339*7c478bd9Sstevel@tonic-gate * implementation assumes that callers will have a SIGALRM handler installed. 340*7c478bd9Sstevel@tonic-gate */ 341*7c478bd9Sstevel@tonic-gate static void 342*7c478bd9Sstevel@tonic-gate fmd_native_wait(hrtime_t delta) 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate timespec_t tv; 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate tv.tv_sec = delta / NANOSEC; 347*7c478bd9Sstevel@tonic-gate tv.tv_nsec = delta % NANOSEC; 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate (void) nanosleep(&tv, NULL); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate static void 353*7c478bd9Sstevel@tonic-gate fmd_native_cancel(pthread_t tid) 354*7c478bd9Sstevel@tonic-gate { 355*7c478bd9Sstevel@tonic-gate (void) pthread_kill(tid, SIGALRM); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate static void * 359*7c478bd9Sstevel@tonic-gate fmd_time_nop(void) 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate return (NULL); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate const fmd_timeops_t fmd_timeops_native = { 365*7c478bd9Sstevel@tonic-gate (void *(*)())fmd_time_nop, /* fto_init */ 366*7c478bd9Sstevel@tonic-gate (void (*)())fmd_time_nop, /* fto_fini */ 367*7c478bd9Sstevel@tonic-gate gettimeofday, /* fto_gettimeofday */ 368*7c478bd9Sstevel@tonic-gate gethrtime, /* fto_gethrtime */ 369*7c478bd9Sstevel@tonic-gate (void (*)())fmd_time_nop, /* fto_addhrtime */ 370*7c478bd9Sstevel@tonic-gate fmd_native_wait, /* fto_waithrtime */ 371*7c478bd9Sstevel@tonic-gate fmd_native_cancel, /* fto_waitcancel */ 372*7c478bd9Sstevel@tonic-gate }; 373*7c478bd9Sstevel@tonic-gate 374*7c478bd9Sstevel@tonic-gate const fmd_timeops_t fmd_timeops_simulated = { 375*7c478bd9Sstevel@tonic-gate fmd_simulator_init, /* fto_init */ 376*7c478bd9Sstevel@tonic-gate fmd_simulator_fini, /* fto_fini */ 377*7c478bd9Sstevel@tonic-gate fmd_simulator_tod, /* fto_gettimeofday */ 378*7c478bd9Sstevel@tonic-gate fmd_simulator_hrt, /* fto_gethrtime */ 379*7c478bd9Sstevel@tonic-gate fmd_simulator_add, /* fto_addhrtime */ 380*7c478bd9Sstevel@tonic-gate fmd_simulator_wait, /* fto_waithrtime */ 381*7c478bd9Sstevel@tonic-gate fmd_simulator_cancel, /* fto_waitcancel */ 382*7c478bd9Sstevel@tonic-gate }; 383