| /* Copyright (c) 2015 Google Inc | 
 |  * Kevin Klues <klueska@google.com> | 
 |  * See LICENSE for details. */ | 
 |  | 
 | #include <unistd.h> | 
 | #include <pthread.h> | 
 | #include <time.h> | 
 | #include <ros/time.h> | 
 | #include <utest/utest.h> | 
 |  | 
 | TEST_SUITE("SLEEP"); | 
 |  | 
 | /* Offset in microseconds to account for processing overhead, etc.. */ | 
 | uint64_t offset_usec = 500; | 
 | /* Number of times to run each test. Take the minimum of the results. */ | 
 | const int NUM_ITERATIONS = 5; | 
 |  | 
 | bool test_nanosleep(void) | 
 | { | 
 | 	const struct timespec times[] = { | 
 | 		{0, 0}, | 
 | 		{0, 1}, | 
 | 		{0, 999}, | 
 | 		{0, 1000}, | 
 | 		{0, 1001}, | 
 | 		{1, 0}, | 
 | 		{1, 1}, | 
 | 		{1, 999}, | 
 | 		{1, 1000}, | 
 | 		{1, 1001}, | 
 | 		{2, 123456789}, | 
 | 	}; | 
 |  | 
 | 	#define check_ntimes(idx, lbound, ubound) \ | 
 | 	{ \ | 
 | 		uint64_t tsc, diff_usec = INT_MAX; \ | 
 | 		for (int i = 0; i < NUM_ITERATIONS; i++) { \ | 
 | 			tsc = read_tsc(); \ | 
 | 			nanosleep(×[idx], NULL); \ | 
 | 			diff_usec = MIN(diff_usec, tsc2usec(read_tsc() - tsc)); \ | 
 | 		} \ | 
 | 		UT_ASSERT_M("Sleep finished too soon", diff_usec >= lbound); \ | 
 | 		UT_ASSERT_M("Sleep finished too late", diff_usec <= ubound); \ | 
 | 	} | 
 |  | 
 | 	check_ntimes(0, 0, offset_usec + 0); | 
 | 	check_ntimes(1, 0, offset_usec + 1); | 
 | 	check_ntimes(2, 0, offset_usec + 1); | 
 | 	check_ntimes(3, 0, offset_usec + 2); | 
 | 	check_ntimes(4, 0, offset_usec + 2); | 
 | 	check_ntimes(5, 1000000, offset_usec + 1000000); | 
 | 	check_ntimes(6, 1000000, offset_usec + 1000001); | 
 | 	check_ntimes(7, 1000000, offset_usec + 1000001); | 
 | 	check_ntimes(8, 1000000, offset_usec + 1000002); | 
 | 	check_ntimes(9, 1000000, offset_usec + 1000002); | 
 | 	check_ntimes(10, 2000000, offset_usec + 2123456); | 
 |  | 
 | 	/* TODO: Check abort path with 'remaining' parameter. */ | 
 | 	return true; | 
 | } | 
 |  | 
 | bool test_usleep(void) | 
 | { | 
 | 	const useconds_t times[] = { | 
 | 		0, 1, 1000, 2000, 1000000, 2000000 | 
 | 	}; | 
 |  | 
 | 	#define check_utimes(idx, lbound, ubound) \ | 
 | 	{ \ | 
 | 		uint64_t tsc, diff_usec = INT_MAX; \ | 
 | 		for (int i = 0; i < NUM_ITERATIONS; i++) { \ | 
 | 			tsc = read_tsc(); \ | 
 | 			usleep(times[idx]); \ | 
 | 			diff_usec = MIN(diff_usec, tsc2usec(read_tsc() - tsc)); \ | 
 | 		} \ | 
 | 		UT_ASSERT_M("Sleep finished too soon", diff_usec >= lbound); \ | 
 | 		UT_ASSERT_M("Sleep finished too late", diff_usec <= ubound); \ | 
 | 	} | 
 |  | 
 | 	check_utimes(0, 0, offset_usec + 0); | 
 | 	check_utimes(1, 1, offset_usec + 1); | 
 | 	check_utimes(2, 1000, offset_usec + 1001); | 
 | 	check_utimes(3, 2000, offset_usec + 20001); | 
 | 	check_utimes(4, 1000000, offset_usec + 1000001); | 
 | 	check_utimes(5, 2000000, offset_usec + 2000001); | 
 | 	return true; | 
 | } | 
 |  | 
 | bool test_sleep(void) | 
 | { | 
 | 	const unsigned int times[] = { | 
 | 		0, 1, 2, 3, 4, 5 | 
 | 	}; | 
 |  | 
 | 	#define check_times(idx, lbound, ubound) \ | 
 | 	{ \ | 
 | 		uint64_t tsc, diff_sec = INT_MAX; \ | 
 | 		for (int i = 0; i < NUM_ITERATIONS; i++) { \ | 
 | 			tsc = read_tsc(); \ | 
 | 			sleep(times[idx]); \ | 
 | 			diff_sec = MIN(diff_sec, tsc2sec(read_tsc() - tsc)); \ | 
 | 		} \ | 
 | 		UT_ASSERT_M("Sleep finished too soon", diff_sec >= lbound); \ | 
 | 		UT_ASSERT_M("Sleep finished too late", diff_sec <= ubound); \ | 
 | 	} | 
 |  | 
 | 	check_times(0, 0, 1); | 
 | 	check_times(1, 1, 2); | 
 | 	check_times(2, 2, 3); | 
 | 	check_times(3, 3, 4); | 
 | 	check_times(4, 4, 5); | 
 | 	check_times(5, 5, 6); | 
 | 	return true; | 
 | } | 
 |  | 
 | struct utest utests[] = { | 
 | 	UTEST_REG(nanosleep), | 
 | 	UTEST_REG(usleep), | 
 | 	UTEST_REG(sleep), | 
 | }; | 
 | int num_utests = sizeof(utests) / sizeof(struct utest); | 
 |  | 
 | int main(int argc, char *argv[]) | 
 | { | 
 | 	char **whitelist = &argv[1]; | 
 | 	int whitelist_len = argc - 1; | 
 |  | 
 | 	RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len); | 
 | } |