root/tools/testing/selftests/timers/posix_timers.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. user_loop
  2. kernel_loop
  3. idle_loop
  4. sig_handler
  5. check_diff
  6. check_itimer
  7. check_timer_create
  8. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
   4  *
   5  * Selftests for a few posix timers interface.
   6  *
   7  * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
   8  */
   9 
  10 #include <sys/time.h>
  11 #include <stdio.h>
  12 #include <signal.h>
  13 #include <unistd.h>
  14 #include <time.h>
  15 #include <pthread.h>
  16 
  17 #include "../kselftest.h"
  18 
  19 #define DELAY 2
  20 #define USECS_PER_SEC 1000000
  21 
  22 static volatile int done;
  23 
  24 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
  25 static void user_loop(void)
  26 {
  27         while (!done);
  28 }
  29 
  30 /*
  31  * Try to spend as much time as possible in kernelspace
  32  * to elapse ITIMER_PROF.
  33  */
  34 static void kernel_loop(void)
  35 {
  36         void *addr = sbrk(0);
  37         int err = 0;
  38 
  39         while (!done && !err) {
  40                 err = brk(addr + 4096);
  41                 err |= brk(addr);
  42         }
  43 }
  44 
  45 /*
  46  * Sleep until ITIMER_REAL expiration.
  47  */
  48 static void idle_loop(void)
  49 {
  50         pause();
  51 }
  52 
  53 static void sig_handler(int nr)
  54 {
  55         done = 1;
  56 }
  57 
  58 /*
  59  * Check the expected timer expiration matches the GTOD elapsed delta since
  60  * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
  61  */
  62 static int check_diff(struct timeval start, struct timeval end)
  63 {
  64         long long diff;
  65 
  66         diff = end.tv_usec - start.tv_usec;
  67         diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
  68 
  69         if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
  70                 printf("Diff too high: %lld..", diff);
  71                 return -1;
  72         }
  73 
  74         return 0;
  75 }
  76 
  77 static int check_itimer(int which)
  78 {
  79         int err;
  80         struct timeval start, end;
  81         struct itimerval val = {
  82                 .it_value.tv_sec = DELAY,
  83         };
  84 
  85         printf("Check itimer ");
  86 
  87         if (which == ITIMER_VIRTUAL)
  88                 printf("virtual... ");
  89         else if (which == ITIMER_PROF)
  90                 printf("prof... ");
  91         else if (which == ITIMER_REAL)
  92                 printf("real... ");
  93 
  94         fflush(stdout);
  95 
  96         done = 0;
  97 
  98         if (which == ITIMER_VIRTUAL)
  99                 signal(SIGVTALRM, sig_handler);
 100         else if (which == ITIMER_PROF)
 101                 signal(SIGPROF, sig_handler);
 102         else if (which == ITIMER_REAL)
 103                 signal(SIGALRM, sig_handler);
 104 
 105         err = gettimeofday(&start, NULL);
 106         if (err < 0) {
 107                 perror("Can't call gettimeofday()\n");
 108                 return -1;
 109         }
 110 
 111         err = setitimer(which, &val, NULL);
 112         if (err < 0) {
 113                 perror("Can't set timer\n");
 114                 return -1;
 115         }
 116 
 117         if (which == ITIMER_VIRTUAL)
 118                 user_loop();
 119         else if (which == ITIMER_PROF)
 120                 kernel_loop();
 121         else if (which == ITIMER_REAL)
 122                 idle_loop();
 123 
 124         err = gettimeofday(&end, NULL);
 125         if (err < 0) {
 126                 perror("Can't call gettimeofday()\n");
 127                 return -1;
 128         }
 129 
 130         if (!check_diff(start, end))
 131                 printf("[OK]\n");
 132         else
 133                 printf("[FAIL]\n");
 134 
 135         return 0;
 136 }
 137 
 138 static int check_timer_create(int which)
 139 {
 140         int err;
 141         timer_t id;
 142         struct timeval start, end;
 143         struct itimerspec val = {
 144                 .it_value.tv_sec = DELAY,
 145         };
 146 
 147         printf("Check timer_create() ");
 148         if (which == CLOCK_THREAD_CPUTIME_ID) {
 149                 printf("per thread... ");
 150         } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
 151                 printf("per process... ");
 152         }
 153         fflush(stdout);
 154 
 155         done = 0;
 156         err = timer_create(which, NULL, &id);
 157         if (err < 0) {
 158                 perror("Can't create timer\n");
 159                 return -1;
 160         }
 161         signal(SIGALRM, sig_handler);
 162 
 163         err = gettimeofday(&start, NULL);
 164         if (err < 0) {
 165                 perror("Can't call gettimeofday()\n");
 166                 return -1;
 167         }
 168 
 169         err = timer_settime(id, 0, &val, NULL);
 170         if (err < 0) {
 171                 perror("Can't set timer\n");
 172                 return -1;
 173         }
 174 
 175         user_loop();
 176 
 177         err = gettimeofday(&end, NULL);
 178         if (err < 0) {
 179                 perror("Can't call gettimeofday()\n");
 180                 return -1;
 181         }
 182 
 183         if (!check_diff(start, end))
 184                 printf("[OK]\n");
 185         else
 186                 printf("[FAIL]\n");
 187 
 188         return 0;
 189 }
 190 
 191 int main(int argc, char **argv)
 192 {
 193         printf("Testing posix timers. False negative may happen on CPU execution \n");
 194         printf("based timers if other threads run on the CPU...\n");
 195 
 196         if (check_itimer(ITIMER_VIRTUAL) < 0)
 197                 return ksft_exit_fail();
 198 
 199         if (check_itimer(ITIMER_PROF) < 0)
 200                 return ksft_exit_fail();
 201 
 202         if (check_itimer(ITIMER_REAL) < 0)
 203                 return ksft_exit_fail();
 204 
 205         if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
 206                 return ksft_exit_fail();
 207 
 208         /*
 209          * It's unfortunately hard to reliably test a timer expiration
 210          * on parallel multithread cputime. We could arm it to expire
 211          * on DELAY * nr_threads, with nr_threads busy looping, then wait
 212          * the normal DELAY since the time is elapsing nr_threads faster.
 213          * But for that we need to ensure we have real physical free CPUs
 214          * to ensure true parallelism. So test only one thread until we
 215          * find a better solution.
 216          */
 217         if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
 218                 return ksft_exit_fail();
 219 
 220         return ksft_exit_pass();
 221 }

/* [<][>][^][v][top][bottom][index][help] */