17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*e4b86885SCheng Sean Ye * Common Development and Distribution License (the "License"). 6*e4b86885SCheng Sean Ye * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*e4b86885SCheng Sean Ye 227c478bd9Sstevel@tonic-gate /* 23*e4b86885SCheng Sean Ye * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h> 287c478bd9Sstevel@tonic-gate #include <signal.h> 297c478bd9Sstevel@tonic-gate #include <limits.h> 307c478bd9Sstevel@tonic-gate #include <time.h> 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <fmd_time.h> 337c478bd9Sstevel@tonic-gate #include <fmd_alloc.h> 347c478bd9Sstevel@tonic-gate #include <fmd_error.h> 357c478bd9Sstevel@tonic-gate #include <fmd_subr.h> 367c478bd9Sstevel@tonic-gate #include <fmd.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate void 397c478bd9Sstevel@tonic-gate fmd_time_gettimeofday(struct timeval *tvp) 407c478bd9Sstevel@tonic-gate { 417c478bd9Sstevel@tonic-gate if (fmd.d_clockops->fto_gettimeofday(tvp, NULL) != 0) 427c478bd9Sstevel@tonic-gate fmd_panic("failed to read time-of-day clock"); 437c478bd9Sstevel@tonic-gate } 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate hrtime_t 467c478bd9Sstevel@tonic-gate fmd_time_gethrtime(void) 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate return (fmd.d_clockops->fto_gethrtime()); 497c478bd9Sstevel@tonic-gate } 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate void 527c478bd9Sstevel@tonic-gate fmd_time_addhrtime(hrtime_t delta) 537c478bd9Sstevel@tonic-gate { 547c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_addhrtime(delta); 557c478bd9Sstevel@tonic-gate } 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate void 587c478bd9Sstevel@tonic-gate fmd_time_waithrtime(hrtime_t delta) 597c478bd9Sstevel@tonic-gate { 607c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_waithrtime(delta); 617c478bd9Sstevel@tonic-gate } 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate void 647c478bd9Sstevel@tonic-gate fmd_time_waitcancel(pthread_t tid) 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate fmd.d_clockops->fto_waitcancel(tid); 677c478bd9Sstevel@tonic-gate } 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * To synchronize TOD with a gethrtime() source, we repeatedly sample TOD in 717c478bd9Sstevel@tonic-gate * between two calls to gethrtime(), which places a reasonably tight bound on 727c478bd9Sstevel@tonic-gate * the high-resolution time that matches the TOD value we sampled. We repeat 737c478bd9Sstevel@tonic-gate * this process several times and ultimately select the sample where the two 747c478bd9Sstevel@tonic-gate * values of gethrtime() were closest. We then assign the average of those 757c478bd9Sstevel@tonic-gate * two high-resolution times to be the gethrtime() associated with that TOD. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate void 787c478bd9Sstevel@tonic-gate fmd_time_sync(fmd_timeval_t *ftv, hrtime_t *hrp, uint_t samples) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate const fmd_timeops_t *ftop = fmd.d_clockops; 817c478bd9Sstevel@tonic-gate hrtime_t hrtbase, hrtmin = INT64_MAX; 827c478bd9Sstevel@tonic-gate struct timeval todbase; 837c478bd9Sstevel@tonic-gate uint_t i; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate for (i = 0; i < samples; i++) { 867c478bd9Sstevel@tonic-gate hrtime_t t0, t1, delta; 877c478bd9Sstevel@tonic-gate struct timeval tod; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate t0 = ftop->fto_gethrtime(); 907c478bd9Sstevel@tonic-gate (void) ftop->fto_gettimeofday(&tod, NULL); 917c478bd9Sstevel@tonic-gate t1 = ftop->fto_gethrtime(); 927c478bd9Sstevel@tonic-gate delta = t1 - t0; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if (delta < hrtmin) { 957c478bd9Sstevel@tonic-gate hrtmin = delta; 967c478bd9Sstevel@tonic-gate hrtbase = t0 + delta / 2; 977c478bd9Sstevel@tonic-gate todbase = tod; 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if (ftv != NULL) { 1027c478bd9Sstevel@tonic-gate ftv->ftv_sec = todbase.tv_sec; 1037c478bd9Sstevel@tonic-gate ftv->ftv_nsec = todbase.tv_usec * (NANOSEC / MICROSEC); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate if (hrp != NULL) 1077c478bd9Sstevel@tonic-gate *hrp = hrtbase; 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* 1117c478bd9Sstevel@tonic-gate * Convert a high-resolution timestamp into 64-bit seconds and nanoseconds. 1127c478bd9Sstevel@tonic-gate * For efficiency, the multiplication and division are expanded using the 1137c478bd9Sstevel@tonic-gate * clever algorithm originally designed for the kernel in hrt2ts(). Refer to 1147c478bd9Sstevel@tonic-gate * the comments in uts/common/os/timers.c for an explanation of how it works. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate static void 1177c478bd9Sstevel@tonic-gate fmd_time_hrt2ftv(hrtime_t hrt, fmd_timeval_t *ftv) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate uint32_t sec, nsec, tmp; 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate tmp = (uint32_t)(hrt >> 30); 1227c478bd9Sstevel@tonic-gate sec = tmp - (tmp >> 2); 1237c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 5); 1247c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 1); 1257c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 6) + 7; 1267c478bd9Sstevel@tonic-gate sec = tmp - (sec >> 3); 1277c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 1); 1287c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 3); 1297c478bd9Sstevel@tonic-gate sec = tmp + (sec >> 4); 1307c478bd9Sstevel@tonic-gate tmp = (sec << 7) - sec - sec - sec; 1317c478bd9Sstevel@tonic-gate tmp = (tmp << 7) - tmp - tmp - tmp; 1327c478bd9Sstevel@tonic-gate tmp = (tmp << 7) - tmp - tmp - tmp; 1337c478bd9Sstevel@tonic-gate nsec = (uint32_t)hrt - (tmp << 9); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate while (nsec >= NANOSEC) { 1367c478bd9Sstevel@tonic-gate nsec -= NANOSEC; 1377c478bd9Sstevel@tonic-gate sec++; 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate ftv->ftv_sec = sec; 1417c478bd9Sstevel@tonic-gate ftv->ftv_nsec = nsec; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* 1457c478bd9Sstevel@tonic-gate * Convert a high-resolution time from gethrtime() to a TOD (fmd_timeval_t). 1467c478bd9Sstevel@tonic-gate * We convert 'tod_base' to nanoseconds, adjust it based on the difference 1477c478bd9Sstevel@tonic-gate * between the corresponding 'hrt_base' and the event high-res time 'hrt', 1487c478bd9Sstevel@tonic-gate * and then repack the result into ftv_sec and ftv_nsec for our output. 1497c478bd9Sstevel@tonic-gate */ 1507c478bd9Sstevel@tonic-gate void 1517c478bd9Sstevel@tonic-gate fmd_time_hrt2tod(hrtime_t hrt_base, const fmd_timeval_t *tod_base, 1527c478bd9Sstevel@tonic-gate hrtime_t hrt, fmd_timeval_t *ftv) 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate fmd_time_hrt2ftv(tod_base->ftv_sec * NANOSEC + 1557c478bd9Sstevel@tonic-gate tod_base->ftv_nsec + (hrt - hrt_base), ftv); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate /* 1597c478bd9Sstevel@tonic-gate * Convert a TOD (fmd_timeval_t) to a high-resolution time from gethrtime(). 1607c478bd9Sstevel@tonic-gate * Note that since TOD occurred in the past, the resulting value may be a 1617c478bd9Sstevel@tonic-gate * negative number according the current gethrtime() clock value. 1627c478bd9Sstevel@tonic-gate */ 1637c478bd9Sstevel@tonic-gate void 1647c478bd9Sstevel@tonic-gate fmd_time_tod2hrt(hrtime_t hrt_base, const fmd_timeval_t *tod_base, 1657c478bd9Sstevel@tonic-gate const fmd_timeval_t *ftv, hrtime_t *hrtp) 1667c478bd9Sstevel@tonic-gate { 1677c478bd9Sstevel@tonic-gate hrtime_t tod_hrt = tod_base->ftv_sec * NANOSEC + tod_base->ftv_nsec; 1687c478bd9Sstevel@tonic-gate hrtime_t ftv_hrt = ftv->ftv_sec * NANOSEC + ftv->ftv_nsec; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate *hrtp = hrt_base - (tod_hrt - ftv_hrt); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * Adjust a high-resolution time based on the low bits of time stored in ENA. 1757c478bd9Sstevel@tonic-gate * The assumption here in that ENA won't wrap between the time it is computed 1767c478bd9Sstevel@tonic-gate * and the time the error is queued (when we capture a full 64-bits of hrtime). 1777c478bd9Sstevel@tonic-gate * We extract the relevant ENA time bits as 't0' and subtract the difference 1787c478bd9Sstevel@tonic-gate * between these bits and the corresponding low bits of 'hrt' from 'hrt'. 179*e4b86885SCheng Sean Ye * 180*e4b86885SCheng Sean Ye * Under xVM dom0, the UE ereport is prepared after panic, therefore 181*e4b86885SCheng Sean Ye * the full 64-bit hrtime of 't0' can be bigger than 'hrt'. In such case, 182*e4b86885SCheng Sean Ye * we should just return 'hrt'. 183*e4b86885SCheng Sean Ye * 184*e4b86885SCheng Sean Ye * 't0' contains only the low bits of 64bit hrtime. It is tricky to tell 185*e4b86885SCheng Sean Ye * whether 'hrt' or 't0' happened first. We assume there should be short 186*e4b86885SCheng Sean Ye * period between 'hrt' and 't0', therefore to check which one came first, we 187*e4b86885SCheng Sean Ye * test their subtraction against the highest bit of mask, if the bit is not 188*e4b86885SCheng Sean Ye * set, then 't0' is earlier. This is equivalent to 189*e4b86885SCheng Sean Ye * ((hrt - t0) & mask) < ((mask + 1) / 2) 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate hrtime_t 1927c478bd9Sstevel@tonic-gate fmd_time_ena2hrt(hrtime_t hrt, uint64_t ena) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate hrtime_t t0, mask; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate switch (ENA_FORMAT(ena)) { 1977c478bd9Sstevel@tonic-gate case FM_ENA_FMT1: 1987c478bd9Sstevel@tonic-gate t0 = (ena & ENA_FMT1_TIME_MASK) >> ENA_FMT1_TIME_SHFT; 1997c478bd9Sstevel@tonic-gate mask = ENA_FMT1_TIME_MASK >> ENA_FMT1_TIME_SHFT; 200*e4b86885SCheng Sean Ye if (((hrt - t0) & ((mask + 1) >> 1)) == 0) 2017c478bd9Sstevel@tonic-gate hrt -= (hrt - t0) & mask; 2027c478bd9Sstevel@tonic-gate break; 2037c478bd9Sstevel@tonic-gate case FM_ENA_FMT2: 2047c478bd9Sstevel@tonic-gate t0 = (ena & ENA_FMT2_TIME_MASK) >> ENA_FMT2_TIME_SHFT; 2057c478bd9Sstevel@tonic-gate mask = ENA_FMT2_TIME_MASK >> ENA_FMT2_TIME_SHFT; 206*e4b86885SCheng Sean Ye if (((hrt - t0) & ((mask + 1) >> 1)) == 0) 2077c478bd9Sstevel@tonic-gate hrt -= (hrt - t0) & mask; 2087c478bd9Sstevel@tonic-gate break; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate return (hrt); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * To implement a simulated clock, we keep track of an hrtime_t value which 2167c478bd9Sstevel@tonic-gate * starts at zero and is incremented only by fmd_time_addhrtime() (i.e. when 2177c478bd9Sstevel@tonic-gate * the driver of the simulation requests that the clock advance). We sample 2187c478bd9Sstevel@tonic-gate * the native time-of-day clock once at the start of the simulation and then 2197c478bd9Sstevel@tonic-gate * return subsequent time-of-day values by adjusting TOD using the hrtime_t 2207c478bd9Sstevel@tonic-gate * clock setting. Simulated nanosleep (fmd_time_waithrtime() entry point) is 2217c478bd9Sstevel@tonic-gate * implemented by waiting on fts->fts_cv for the hrtime_t to increment. 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate static void * 2247c478bd9Sstevel@tonic-gate fmd_simulator_init(void) 2257c478bd9Sstevel@tonic-gate { 2267c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd_alloc(sizeof (fmd_timesim_t), FMD_SLEEP); 2277c478bd9Sstevel@tonic-gate struct timeval tv; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&fts->fts_lock, NULL); 2307c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&fts->fts_cv, NULL); 2317c478bd9Sstevel@tonic-gate (void) gettimeofday(&tv, NULL); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate fts->fts_tod = (hrtime_t)tv.tv_sec * NANOSEC + 2347c478bd9Sstevel@tonic-gate (hrtime_t)tv.tv_usec * (NANOSEC / MICROSEC); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate fts->fts_hrt = 0; 2377c478bd9Sstevel@tonic-gate fts->fts_cancel = 0; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_TMR, "simulator tod base tv_sec=%lx hrt=%llx\n", 2407c478bd9Sstevel@tonic-gate tv.tv_sec, fts->fts_tod); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate return (fts); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate static void 2467c478bd9Sstevel@tonic-gate fmd_simulator_fini(void *fts) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate if (fts != NULL) 2497c478bd9Sstevel@tonic-gate fmd_free(fts, sizeof (fmd_timesim_t)); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2537c478bd9Sstevel@tonic-gate static int 2547c478bd9Sstevel@tonic-gate fmd_simulator_tod(struct timeval *tvp, void *tzp) 2557c478bd9Sstevel@tonic-gate { 2567c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 2577c478bd9Sstevel@tonic-gate hrtime_t tod, hrt, sec, rem; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate tod = fts->fts_tod; 2627c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate sec = tod / NANOSEC + hrt / NANOSEC; 2677c478bd9Sstevel@tonic-gate rem = tod % NANOSEC + hrt % NANOSEC; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate tvp->tv_sec = sec + rem / NANOSEC; 2707c478bd9Sstevel@tonic-gate tvp->tv_usec = (rem % NANOSEC) / (NANOSEC / MICROSEC); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate return (0); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate static hrtime_t 2767c478bd9Sstevel@tonic-gate fmd_simulator_hrt(void) 2777c478bd9Sstevel@tonic-gate { 2787c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 2797c478bd9Sstevel@tonic-gate hrtime_t hrt; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 2827c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt; 2837c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate return (hrt); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate static void 2897c478bd9Sstevel@tonic-gate fmd_simulator_add(hrtime_t delta) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (fts->fts_hrt + delta < fts->fts_hrt) 2967c478bd9Sstevel@tonic-gate fts->fts_hrt = INT64_MAX; /* do not increment past apocalypse */ 2977c478bd9Sstevel@tonic-gate else 2987c478bd9Sstevel@tonic-gate fts->fts_hrt += delta; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_TMR, "hrt clock set %llx", fts->fts_hrt)); 3017c478bd9Sstevel@tonic-gate fmd_dprintf(FMD_DBG_TMR, "hrt clock set %llx\n", fts->fts_hrt); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&fts->fts_cv); 304d9638e54Smws (void) pthread_mutex_unlock(&fts->fts_lock); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate static void 3087c478bd9Sstevel@tonic-gate fmd_simulator_wait(hrtime_t delta) 3097c478bd9Sstevel@tonic-gate { 3107c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 3117c478bd9Sstevel@tonic-gate uint64_t hrt; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * If the delta causes time to wrap because we've reached the simulated 3177c478bd9Sstevel@tonic-gate * apocalypse, then wait forever. We make 'hrt' unsigned so that the 3187c478bd9Sstevel@tonic-gate * while-loop comparison fts_hrt < UINT64_MAX will always return true. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate if (fts->fts_hrt + delta < fts->fts_hrt) 3217c478bd9Sstevel@tonic-gate hrt = UINT64_MAX; 3227c478bd9Sstevel@tonic-gate else 3237c478bd9Sstevel@tonic-gate hrt = fts->fts_hrt + delta; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate while (fts->fts_hrt < hrt && fts->fts_cancel == 0) 3267c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&fts->fts_cv, &fts->fts_lock); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate if (fts->fts_cancel != 0) 3297c478bd9Sstevel@tonic-gate fts->fts_cancel--; /* cancel has been processed */ 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&fts->fts_lock); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3357c478bd9Sstevel@tonic-gate static void 3367c478bd9Sstevel@tonic-gate fmd_simulator_cancel(pthread_t tid) 3377c478bd9Sstevel@tonic-gate { 3387c478bd9Sstevel@tonic-gate fmd_timesim_t *fts = fmd.d_clockptr; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&fts->fts_lock); 3417c478bd9Sstevel@tonic-gate fts->fts_cancel++; 3427c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&fts->fts_cv); 343d9638e54Smws (void) pthread_mutex_unlock(&fts->fts_lock); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * Native time is implemented by calls to gethrtime() and gettimeofday(), which 3487c478bd9Sstevel@tonic-gate * are stored directly in the native time ops-vector defined below. To wait on 3497c478bd9Sstevel@tonic-gate * the native clock we use nanosleep(), which we can abort using a signal. The 3507c478bd9Sstevel@tonic-gate * implementation assumes that callers will have a SIGALRM handler installed. 3517c478bd9Sstevel@tonic-gate */ 3527c478bd9Sstevel@tonic-gate static void 3537c478bd9Sstevel@tonic-gate fmd_native_wait(hrtime_t delta) 3547c478bd9Sstevel@tonic-gate { 3557c478bd9Sstevel@tonic-gate timespec_t tv; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate tv.tv_sec = delta / NANOSEC; 3587c478bd9Sstevel@tonic-gate tv.tv_nsec = delta % NANOSEC; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate (void) nanosleep(&tv, NULL); 3617c478bd9Sstevel@tonic-gate } 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate static void 3647c478bd9Sstevel@tonic-gate fmd_native_cancel(pthread_t tid) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate (void) pthread_kill(tid, SIGALRM); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate static void * 3707c478bd9Sstevel@tonic-gate fmd_time_nop(void) 3717c478bd9Sstevel@tonic-gate { 3727c478bd9Sstevel@tonic-gate return (NULL); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate const fmd_timeops_t fmd_timeops_native = { 3767c478bd9Sstevel@tonic-gate (void *(*)())fmd_time_nop, /* fto_init */ 3777c478bd9Sstevel@tonic-gate (void (*)())fmd_time_nop, /* fto_fini */ 3787c478bd9Sstevel@tonic-gate gettimeofday, /* fto_gettimeofday */ 3797c478bd9Sstevel@tonic-gate gethrtime, /* fto_gethrtime */ 3807c478bd9Sstevel@tonic-gate (void (*)())fmd_time_nop, /* fto_addhrtime */ 3817c478bd9Sstevel@tonic-gate fmd_native_wait, /* fto_waithrtime */ 3827c478bd9Sstevel@tonic-gate fmd_native_cancel, /* fto_waitcancel */ 3837c478bd9Sstevel@tonic-gate }; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate const fmd_timeops_t fmd_timeops_simulated = { 3867c478bd9Sstevel@tonic-gate fmd_simulator_init, /* fto_init */ 3877c478bd9Sstevel@tonic-gate fmd_simulator_fini, /* fto_fini */ 3887c478bd9Sstevel@tonic-gate fmd_simulator_tod, /* fto_gettimeofday */ 3897c478bd9Sstevel@tonic-gate fmd_simulator_hrt, /* fto_gethrtime */ 3907c478bd9Sstevel@tonic-gate fmd_simulator_add, /* fto_addhrtime */ 3917c478bd9Sstevel@tonic-gate fmd_simulator_wait, /* fto_waithrtime */ 3927c478bd9Sstevel@tonic-gate fmd_simulator_cancel, /* fto_waitcancel */ 3937c478bd9Sstevel@tonic-gate }; 394