18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Selftests for a few posix timers interface. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <sys/time.h> 118c2ecf20Sopenharmony_ci#include <stdio.h> 128c2ecf20Sopenharmony_ci#include <signal.h> 138c2ecf20Sopenharmony_ci#include <unistd.h> 148c2ecf20Sopenharmony_ci#include <time.h> 158c2ecf20Sopenharmony_ci#include <pthread.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "../kselftest.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define DELAY 2 208c2ecf20Sopenharmony_ci#define USECS_PER_SEC 1000000 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic volatile int done; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* Busy loop in userspace to elapse ITIMER_VIRTUAL */ 258c2ecf20Sopenharmony_cistatic void user_loop(void) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci while (!done); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Try to spend as much time as possible in kernelspace 328c2ecf20Sopenharmony_ci * to elapse ITIMER_PROF. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_cistatic void kernel_loop(void) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci void *addr = sbrk(0); 378c2ecf20Sopenharmony_ci int err = 0; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci while (!done && !err) { 408c2ecf20Sopenharmony_ci err = brk(addr + 4096); 418c2ecf20Sopenharmony_ci err |= brk(addr); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Sleep until ITIMER_REAL expiration. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistatic void idle_loop(void) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci pause(); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void sig_handler(int nr) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci done = 1; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Check the expected timer expiration matches the GTOD elapsed delta since 608c2ecf20Sopenharmony_ci * we armed the timer. Keep a 0.5 sec error margin due to various jitter. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic int check_diff(struct timeval start, struct timeval end) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci long long diff; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci diff = end.tv_usec - start.tv_usec; 678c2ecf20Sopenharmony_ci diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) { 708c2ecf20Sopenharmony_ci printf("Diff too high: %lld..", diff); 718c2ecf20Sopenharmony_ci return -1; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int check_itimer(int which) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int err; 808c2ecf20Sopenharmony_ci struct timeval start, end; 818c2ecf20Sopenharmony_ci struct itimerval val = { 828c2ecf20Sopenharmony_ci .it_value.tv_sec = DELAY, 838c2ecf20Sopenharmony_ci }; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci printf("Check itimer "); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (which == ITIMER_VIRTUAL) 888c2ecf20Sopenharmony_ci printf("virtual... "); 898c2ecf20Sopenharmony_ci else if (which == ITIMER_PROF) 908c2ecf20Sopenharmony_ci printf("prof... "); 918c2ecf20Sopenharmony_ci else if (which == ITIMER_REAL) 928c2ecf20Sopenharmony_ci printf("real... "); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci fflush(stdout); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci done = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (which == ITIMER_VIRTUAL) 998c2ecf20Sopenharmony_ci signal(SIGVTALRM, sig_handler); 1008c2ecf20Sopenharmony_ci else if (which == ITIMER_PROF) 1018c2ecf20Sopenharmony_ci signal(SIGPROF, sig_handler); 1028c2ecf20Sopenharmony_ci else if (which == ITIMER_REAL) 1038c2ecf20Sopenharmony_ci signal(SIGALRM, sig_handler); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci err = gettimeofday(&start, NULL); 1068c2ecf20Sopenharmony_ci if (err < 0) { 1078c2ecf20Sopenharmony_ci perror("Can't call gettimeofday()\n"); 1088c2ecf20Sopenharmony_ci return -1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci err = setitimer(which, &val, NULL); 1128c2ecf20Sopenharmony_ci if (err < 0) { 1138c2ecf20Sopenharmony_ci perror("Can't set timer\n"); 1148c2ecf20Sopenharmony_ci return -1; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (which == ITIMER_VIRTUAL) 1188c2ecf20Sopenharmony_ci user_loop(); 1198c2ecf20Sopenharmony_ci else if (which == ITIMER_PROF) 1208c2ecf20Sopenharmony_ci kernel_loop(); 1218c2ecf20Sopenharmony_ci else if (which == ITIMER_REAL) 1228c2ecf20Sopenharmony_ci idle_loop(); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci err = gettimeofday(&end, NULL); 1258c2ecf20Sopenharmony_ci if (err < 0) { 1268c2ecf20Sopenharmony_ci perror("Can't call gettimeofday()\n"); 1278c2ecf20Sopenharmony_ci return -1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!check_diff(start, end)) 1318c2ecf20Sopenharmony_ci printf("[OK]\n"); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int check_timer_create(int which) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int err; 1418c2ecf20Sopenharmony_ci timer_t id; 1428c2ecf20Sopenharmony_ci struct timeval start, end; 1438c2ecf20Sopenharmony_ci struct itimerspec val = { 1448c2ecf20Sopenharmony_ci .it_value.tv_sec = DELAY, 1458c2ecf20Sopenharmony_ci }; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci printf("Check timer_create() "); 1488c2ecf20Sopenharmony_ci if (which == CLOCK_THREAD_CPUTIME_ID) { 1498c2ecf20Sopenharmony_ci printf("per thread... "); 1508c2ecf20Sopenharmony_ci } else if (which == CLOCK_PROCESS_CPUTIME_ID) { 1518c2ecf20Sopenharmony_ci printf("per process... "); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci fflush(stdout); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci done = 0; 1568c2ecf20Sopenharmony_ci err = timer_create(which, NULL, &id); 1578c2ecf20Sopenharmony_ci if (err < 0) { 1588c2ecf20Sopenharmony_ci perror("Can't create timer\n"); 1598c2ecf20Sopenharmony_ci return -1; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci signal(SIGALRM, sig_handler); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci err = gettimeofday(&start, NULL); 1648c2ecf20Sopenharmony_ci if (err < 0) { 1658c2ecf20Sopenharmony_ci perror("Can't call gettimeofday()\n"); 1668c2ecf20Sopenharmony_ci return -1; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci err = timer_settime(id, 0, &val, NULL); 1708c2ecf20Sopenharmony_ci if (err < 0) { 1718c2ecf20Sopenharmony_ci perror("Can't set timer\n"); 1728c2ecf20Sopenharmony_ci return -1; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci user_loop(); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci err = gettimeofday(&end, NULL); 1788c2ecf20Sopenharmony_ci if (err < 0) { 1798c2ecf20Sopenharmony_ci perror("Can't call gettimeofday()\n"); 1808c2ecf20Sopenharmony_ci return -1; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!check_diff(start, end)) 1848c2ecf20Sopenharmony_ci printf("[OK]\n"); 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci printf("Testing posix timers. False negative may happen on CPU execution \n"); 1948c2ecf20Sopenharmony_ci printf("based timers if other threads run on the CPU...\n"); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (check_itimer(ITIMER_VIRTUAL) < 0) 1978c2ecf20Sopenharmony_ci return ksft_exit_fail(); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (check_itimer(ITIMER_PROF) < 0) 2008c2ecf20Sopenharmony_ci return ksft_exit_fail(); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if (check_itimer(ITIMER_REAL) < 0) 2038c2ecf20Sopenharmony_ci return ksft_exit_fail(); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) 2068c2ecf20Sopenharmony_ci return ksft_exit_fail(); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * It's unfortunately hard to reliably test a timer expiration 2108c2ecf20Sopenharmony_ci * on parallel multithread cputime. We could arm it to expire 2118c2ecf20Sopenharmony_ci * on DELAY * nr_threads, with nr_threads busy looping, then wait 2128c2ecf20Sopenharmony_ci * the normal DELAY since the time is elapsing nr_threads faster. 2138c2ecf20Sopenharmony_ci * But for that we need to ensure we have real physical free CPUs 2148c2ecf20Sopenharmony_ci * to ensure true parallelism. So test only one thread until we 2158c2ecf20Sopenharmony_ci * find a better solution. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) 2188c2ecf20Sopenharmony_ci return ksft_exit_fail(); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return ksft_exit_pass(); 2218c2ecf20Sopenharmony_ci} 222