void ThreadSleepMs(uint64_t msec) { struct nacl_abi_timespec nap_duration; nap_duration.tv_sec = (nacl_abi_time_t) (msec / 1000); nap_duration.tv_nsec = (long) (msec % 1000); NaClNanosleep(&nap_duration, (struct nacl_abi_timespec *) NULL); }
int32_t NaClSysNanosleep(struct NaClAppThread *natp, struct nacl_abi_timespec *req, struct nacl_abi_timespec *rem) { uintptr_t sys_req; int retval = -NACL_ABI_EINVAL; struct nacl_abi_timespec host_req; UNREFERENCED_PARAMETER(rem); NaClLog(4, "NaClSysNanosleep(%08x)\n", (uintptr_t) req); NaClSysCommonThreadSyscallEnter(natp); sys_req = NaClUserToSysAddrRange(natp->nap, (uintptr_t) req, sizeof *req); if (kNaClBadAddress == sys_req) { retval = -NACL_ABI_EFAULT; goto cleanup; } /* copy once */ host_req = *(struct nacl_abi_timespec *) sys_req; /* * We assume that we do not need to normalize the time request values. * * If bogus values can cause the underlying OS to get into trouble, * then we need more checking here. */ NaClLog(4, "NaClSysNanosleep(time = %d.%09ld S)\n", host_req.tv_sec, host_req.tv_nsec); retval = NaClNanosleep(&host_req, NULL); cleanup: NaClSysCommonThreadSyscallLeave(natp); return retval; }
/* * ClockMonotonicAccuracyTest samples the NACL_ABI_CLOCK_MONOTONIC * clock before and after invoking NaClNanosleep and computes the time * delta. The test is considered to pass if the time delta is close * to the requested value. "Close" is a per-host-OS attribute, thus * the above testing parameters. */ int ClockMonotonicAccuracyTest(uint64_t sleep_nanos) { int num_failures = 0; int err; struct nacl_abi_timespec t_start; struct nacl_abi_timespec t_sleep; struct nacl_abi_timespec t_end; uint64_t elapsed_nanos; uint64_t elapsed_lower_bound; uint64_t elapsed_upper_bound; t_sleep.tv_sec = sleep_nanos / NANOS_PER_UNIT; t_sleep.tv_nsec = sleep_nanos % NANOS_PER_UNIT; printf("\nCLOCK_MONOTONIC accuracy test:\n"); if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_MONOTONIC, &t_start))) { fprintf(stderr, "nacl_clock_test: NaClClockGetTime (start) failed, error %d\n", err); ++num_failures; goto done; } for (;;) { err = NaClNanosleep(&t_sleep, &t_sleep); if (0 == err) { break; } if (-NACL_ABI_EINTR == err) { /* interrupted syscall: sleep some more */ continue; } fprintf(stderr, "nacl_clock_test: NaClNanoSleep failed, error %d\n", err); num_failures++; goto done; } if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_MONOTONIC, &t_end))) { fprintf(stderr, "nacl_clock_test: NaClClockGetTime (end) failed, error %d\n", err); return 1; } elapsed_nanos = (t_end.tv_sec - t_start.tv_sec) * NANOS_PER_UNIT + (t_end.tv_nsec - t_start.tv_nsec) + g_slop_ms * NANOS_PER_MILLI; elapsed_lower_bound = sleep_nanos; elapsed_upper_bound = (uint64_t) (sleep_nanos * g_fuzzy_factor + g_syscall_overhead); printf("requested sleep: %20"NACL_PRIu64" nS\n", sleep_nanos); printf("actual elapsed sleep: %20"NACL_PRIu64" nS\n", elapsed_nanos); printf("sleep lower bound: %20"NACL_PRIu64" nS\n", elapsed_lower_bound); printf("sleep upper bound: %20"NACL_PRIu64" nS\n", elapsed_upper_bound); if (elapsed_nanos < elapsed_lower_bound || elapsed_upper_bound < elapsed_nanos) { printf("discrepancy too large\n"); num_failures++; } done: printf((0 == num_failures) ? "PASSED\n" : "FAILED\n"); return num_failures; }
int32_t NaClSysNanosleep(struct NaClAppThread *natp, struct nacl_abi_timespec *req, struct nacl_abi_timespec *rem) { uintptr_t sys_req; uintptr_t sys_rem; struct nacl_abi_timespec t_sleep; struct nacl_abi_timespec t_rem; struct nacl_abi_timespec *remptr; int retval = -NACL_ABI_EINVAL; NaClLog(3, ("Entered NaClSysNanosleep(0x%08"NACL_PRIxPTR ", 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR"x)\n"), (uintptr_t) natp, (uintptr_t) req, (uintptr_t) rem); NaClSysCommonThreadSyscallEnter(natp); sys_req = NaClUserToSysAddrRange(natp->nap, (uintptr_t) req, sizeof *req); if (kNaClBadAddress == sys_req) { retval = -NACL_ABI_EFAULT; goto cleanup; } if (NULL == rem) { sys_rem = 0; } else { sys_rem = NaClUserToSysAddrRange(natp->nap, (uintptr_t) rem, sizeof *rem); if (kNaClBadAddress == sys_rem) { retval = -NACL_ABI_EFAULT; goto cleanup; } } /* * post-condition: if sys_rem is non-NULL, it's safe to write to * (modulo thread races) and the user code wants the remaining time * written there. */ NaClLog(4, " copying timespec from %08"NACL_PRIxPTR"x\n", sys_req); /* copy once */ t_sleep = *(struct nacl_abi_timespec *) sys_req; remptr = (0 == sys_rem) ? NULL : &t_rem; /* NULL != remptr \equiv NULL != rem */ /* * We assume that we do not need to normalize the time request values. * * If bogus values can cause the underlying OS to get into trouble, * then we need more checking here. */ NaClLog(4, "NaClSysNanosleep(time = %"NACL_PRId64".%09"NACL_PRId64" S)\n", (int64_t) t_sleep.tv_sec, (int64_t) t_sleep.tv_nsec); retval = NaClNanosleep(&t_sleep, remptr); NaClLog(4, "NaClNanosleep returned %d\n", retval); if (-EINTR == retval && NULL != rem) { /* definitely different types, and shape may actually differ too. */ rem = (struct nacl_abi_timespec *) sys_rem; rem->tv_sec = remptr->tv_sec; rem->tv_nsec = remptr->tv_nsec; } cleanup: NaClLog(4, "nanosleep done.\n"); NaClSysCommonThreadSyscallLeave(natp); return retval; }