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