unsigned long hwtimer_arch_now(void) { struct timespec t; DEBUG("hwtimer_arch_now()\n"); _native_syscall_enter(); #ifdef __MACH__ clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); t.tv_sec = mts.tv_sec; t.tv_nsec = mts.tv_nsec; #else if (real_clock_gettime(CLOCK_MONOTONIC, &t) == -1) { err(EXIT_FAILURE, "hwtimer_arch_now: clock_gettime"); } #endif _native_syscall_leave(); native_hwtimer_now = ts2ticks(&t) - time_null; struct timeval tv; ticks2tv(native_hwtimer_now, &tv); DEBUG("hwtimer_arch_now(): it is now %lu s %lu us\n", (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec); DEBUG("hwtimer_arch_now(): returning %lu\n", native_hwtimer_now); return native_hwtimer_now; }
/// Replacement pthread_cond_timedwait() /// /// WARNING: This replacement calls through to the 2.3.2 version of the /// real pthread_cond_timedwait, regardless of the version the calling code /// assumed it would be calling. This will need updating to support other /// libc versions. /// /// WARNING THE SECOND: This assumes that the condition variable was created /// with a condattr that specifies CLOCK_MONOTONIC. /// /// http://blog.fesnel.com/blog/2009/08/25/preloading-with-multiple-symbol-versions/ int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) { struct timespec fixed_time; if (!real_pthread_cond_timedwait) { real_pthread_cond_timedwait = (pthread_cond_timedwait_func_t)(intptr_t)dlvsym(RTLD_NEXT, "pthread_cond_timedwait", "GLIBC_2.3.2"); } // Subtract our fake time and add the real time, this means the // relative delay is correct while allowing the calling code to think // it's woking with absolute time. // // Note we call the fake clock_gettime first, meaning that real_clock_gettime // will be set before the call to it in the next line. struct timespec fake_time; struct timespec real_time; struct timespec delta_time; clock_gettime(CLOCK_MONOTONIC, &fake_time); real_clock_gettime(CLOCK_MONOTONIC, &real_time); ts_sub(*abstime, fake_time, delta_time); ts_add(real_time, delta_time, fixed_time); return real_pthread_cond_timedwait(cond, mutex, &fixed_time); }
void cwtest_completely_control_time() { if (!real_clock_gettime) { real_clock_gettime = (int (*)(clockid_t, struct timespec *))(intptr_t)dlsym(RTLD_NEXT, "clock_gettime"); } if (!real_time) { real_time = (time_t (*)(time_t*))(intptr_t)dlsym(RTLD_NEXT, "time"); } pthread_mutex_lock(&time_lock); completely_control_time = true; // Store the time at which the test scripts took control. Do this for both // clock_gettime() and time(). struct timespec ts; for (unsigned int i = 0; i < (sizeof(supported_clock_ids) / sizeof(supported_clock_ids[0])); ++i) { clockid_t clock_id = supported_clock_ids[i]; real_clock_gettime(clock_id, &ts); abs_timespecs[clock_id] = ts; } abs_time = real_time(NULL); pthread_mutex_unlock(&time_lock); }
unsigned int timer_read(tim_t dev) { if (dev >= TIMER_NUMOF) { return 0; } struct timespec t; DEBUG("timer_read()\n"); _native_syscall_enter(); #ifdef __MACH__ clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); t.tv_sec = mts.tv_sec; t.tv_nsec = mts.tv_nsec; #else if (real_clock_gettime(CLOCK_MONOTONIC, &t) == -1) { err(EXIT_FAILURE, "timer_read: clock_gettime"); } #endif _native_syscall_leave(); return ts2ticks(&t) - time_null; }
/// Replacement clock_gettime. int clock_gettime(clockid_t clk_id, struct timespec *tp) throw () { int rc; if (!real_clock_gettime) { real_clock_gettime = (int (*)(clockid_t, struct timespec *))(intptr_t)dlsym(RTLD_NEXT, "clock_gettime"); } pthread_mutex_lock(&time_lock); if (completely_control_time) { if (abs_timespecs.find(clk_id) != abs_timespecs.end()) { *tp = abs_timespecs[clk_id]; rc = 0; } else { // We don't support this clock ID. Print a warning, and act like an // invalid clock ID has been requested. fprintf(stderr, "WARNING: Clock ID %d is not supported (%s:%d)\n", clk_id, __FILE__, __LINE__); rc = -1; errno = EINVAL; } } else { rc = real_clock_gettime(clk_id, tp); } if (!rc) { ts_add(*tp, time_offset, *tp); } pthread_mutex_unlock(&time_lock); return rc; }