Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
0004  *
0005  * Selftests for a few posix timers interface.
0006  *
0007  * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
0008  */
0009 
0010 #include <sys/time.h>
0011 #include <stdio.h>
0012 #include <signal.h>
0013 #include <unistd.h>
0014 #include <time.h>
0015 #include <pthread.h>
0016 
0017 #include "../kselftest.h"
0018 
0019 #define DELAY 2
0020 #define USECS_PER_SEC 1000000
0021 
0022 static volatile int done;
0023 
0024 /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
0025 static void user_loop(void)
0026 {
0027     while (!done);
0028 }
0029 
0030 /*
0031  * Try to spend as much time as possible in kernelspace
0032  * to elapse ITIMER_PROF.
0033  */
0034 static void kernel_loop(void)
0035 {
0036     void *addr = sbrk(0);
0037     int err = 0;
0038 
0039     while (!done && !err) {
0040         err = brk(addr + 4096);
0041         err |= brk(addr);
0042     }
0043 }
0044 
0045 /*
0046  * Sleep until ITIMER_REAL expiration.
0047  */
0048 static void idle_loop(void)
0049 {
0050     pause();
0051 }
0052 
0053 static void sig_handler(int nr)
0054 {
0055     done = 1;
0056 }
0057 
0058 /*
0059  * Check the expected timer expiration matches the GTOD elapsed delta since
0060  * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
0061  */
0062 static int check_diff(struct timeval start, struct timeval end)
0063 {
0064     long long diff;
0065 
0066     diff = end.tv_usec - start.tv_usec;
0067     diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
0068 
0069     if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
0070         printf("Diff too high: %lld..", diff);
0071         return -1;
0072     }
0073 
0074     return 0;
0075 }
0076 
0077 static int check_itimer(int which)
0078 {
0079     int err;
0080     struct timeval start, end;
0081     struct itimerval val = {
0082         .it_value.tv_sec = DELAY,
0083     };
0084 
0085     printf("Check itimer ");
0086 
0087     if (which == ITIMER_VIRTUAL)
0088         printf("virtual... ");
0089     else if (which == ITIMER_PROF)
0090         printf("prof... ");
0091     else if (which == ITIMER_REAL)
0092         printf("real... ");
0093 
0094     fflush(stdout);
0095 
0096     done = 0;
0097 
0098     if (which == ITIMER_VIRTUAL)
0099         signal(SIGVTALRM, sig_handler);
0100     else if (which == ITIMER_PROF)
0101         signal(SIGPROF, sig_handler);
0102     else if (which == ITIMER_REAL)
0103         signal(SIGALRM, sig_handler);
0104 
0105     err = gettimeofday(&start, NULL);
0106     if (err < 0) {
0107         perror("Can't call gettimeofday()\n");
0108         return -1;
0109     }
0110 
0111     err = setitimer(which, &val, NULL);
0112     if (err < 0) {
0113         perror("Can't set timer\n");
0114         return -1;
0115     }
0116 
0117     if (which == ITIMER_VIRTUAL)
0118         user_loop();
0119     else if (which == ITIMER_PROF)
0120         kernel_loop();
0121     else if (which == ITIMER_REAL)
0122         idle_loop();
0123 
0124     err = gettimeofday(&end, NULL);
0125     if (err < 0) {
0126         perror("Can't call gettimeofday()\n");
0127         return -1;
0128     }
0129 
0130     if (!check_diff(start, end))
0131         printf("[OK]\n");
0132     else
0133         printf("[FAIL]\n");
0134 
0135     return 0;
0136 }
0137 
0138 static int check_timer_create(int which)
0139 {
0140     int err;
0141     timer_t id;
0142     struct timeval start, end;
0143     struct itimerspec val = {
0144         .it_value.tv_sec = DELAY,
0145     };
0146 
0147     printf("Check timer_create() ");
0148     if (which == CLOCK_THREAD_CPUTIME_ID) {
0149         printf("per thread... ");
0150     } else if (which == CLOCK_PROCESS_CPUTIME_ID) {
0151         printf("per process... ");
0152     }
0153     fflush(stdout);
0154 
0155     done = 0;
0156     err = timer_create(which, NULL, &id);
0157     if (err < 0) {
0158         perror("Can't create timer\n");
0159         return -1;
0160     }
0161     signal(SIGALRM, sig_handler);
0162 
0163     err = gettimeofday(&start, NULL);
0164     if (err < 0) {
0165         perror("Can't call gettimeofday()\n");
0166         return -1;
0167     }
0168 
0169     err = timer_settime(id, 0, &val, NULL);
0170     if (err < 0) {
0171         perror("Can't set timer\n");
0172         return -1;
0173     }
0174 
0175     user_loop();
0176 
0177     err = gettimeofday(&end, NULL);
0178     if (err < 0) {
0179         perror("Can't call gettimeofday()\n");
0180         return -1;
0181     }
0182 
0183     if (!check_diff(start, end))
0184         printf("[OK]\n");
0185     else
0186         printf("[FAIL]\n");
0187 
0188     return 0;
0189 }
0190 
0191 int main(int argc, char **argv)
0192 {
0193     printf("Testing posix timers. False negative may happen on CPU execution \n");
0194     printf("based timers if other threads run on the CPU...\n");
0195 
0196     if (check_itimer(ITIMER_VIRTUAL) < 0)
0197         return ksft_exit_fail();
0198 
0199     if (check_itimer(ITIMER_PROF) < 0)
0200         return ksft_exit_fail();
0201 
0202     if (check_itimer(ITIMER_REAL) < 0)
0203         return ksft_exit_fail();
0204 
0205     if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
0206         return ksft_exit_fail();
0207 
0208     /*
0209      * It's unfortunately hard to reliably test a timer expiration
0210      * on parallel multithread cputime. We could arm it to expire
0211      * on DELAY * nr_threads, with nr_threads busy looping, then wait
0212      * the normal DELAY since the time is elapsing nr_threads faster.
0213      * But for that we need to ensure we have real physical free CPUs
0214      * to ensure true parallelism. So test only one thread until we
0215      * find a better solution.
0216      */
0217     if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
0218         return ksft_exit_fail();
0219 
0220     return ksft_exit_pass();
0221 }