Back to home page

OSCL-LXR

 
 

    


0001 /* Make sure timers don't return early
0002  *              by: john stultz (johnstul@us.ibm.com)
0003  *          John Stultz (john.stultz@linaro.org)
0004  *              (C) Copyright IBM 2012
0005  *              (C) Copyright Linaro 2013 2015
0006  *              Licensed under the GPLv2
0007  *
0008  *  To build:
0009  *  $ gcc nanosleep.c -o nanosleep -lrt
0010  *
0011  *   This program is free software: you can redistribute it and/or modify
0012  *   it under the terms of the GNU General Public License as published by
0013  *   the Free Software Foundation, either version 2 of the License, or
0014  *   (at your option) any later version.
0015  *
0016  *   This program is distributed in the hope that it will be useful,
0017  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0019  *   GNU General Public License for more details.
0020  */
0021 
0022 #include <errno.h>
0023 #include <stdio.h>
0024 #include <stdlib.h>
0025 #include <time.h>
0026 #include <sys/time.h>
0027 #include <sys/timex.h>
0028 #include <string.h>
0029 #include <signal.h>
0030 #include "../kselftest.h"
0031 
0032 #define NSEC_PER_SEC 1000000000ULL
0033 
0034 #define CLOCK_REALTIME          0
0035 #define CLOCK_MONOTONIC         1
0036 #define CLOCK_PROCESS_CPUTIME_ID    2
0037 #define CLOCK_THREAD_CPUTIME_ID     3
0038 #define CLOCK_MONOTONIC_RAW     4
0039 #define CLOCK_REALTIME_COARSE       5
0040 #define CLOCK_MONOTONIC_COARSE      6
0041 #define CLOCK_BOOTTIME          7
0042 #define CLOCK_REALTIME_ALARM        8
0043 #define CLOCK_BOOTTIME_ALARM        9
0044 #define CLOCK_HWSPECIFIC        10
0045 #define CLOCK_TAI           11
0046 #define NR_CLOCKIDS         12
0047 
0048 #define UNSUPPORTED 0xf00f
0049 
0050 char *clockstring(int clockid)
0051 {
0052     switch (clockid) {
0053     case CLOCK_REALTIME:
0054         return "CLOCK_REALTIME";
0055     case CLOCK_MONOTONIC:
0056         return "CLOCK_MONOTONIC";
0057     case CLOCK_PROCESS_CPUTIME_ID:
0058         return "CLOCK_PROCESS_CPUTIME_ID";
0059     case CLOCK_THREAD_CPUTIME_ID:
0060         return "CLOCK_THREAD_CPUTIME_ID";
0061     case CLOCK_MONOTONIC_RAW:
0062         return "CLOCK_MONOTONIC_RAW";
0063     case CLOCK_REALTIME_COARSE:
0064         return "CLOCK_REALTIME_COARSE";
0065     case CLOCK_MONOTONIC_COARSE:
0066         return "CLOCK_MONOTONIC_COARSE";
0067     case CLOCK_BOOTTIME:
0068         return "CLOCK_BOOTTIME";
0069     case CLOCK_REALTIME_ALARM:
0070         return "CLOCK_REALTIME_ALARM";
0071     case CLOCK_BOOTTIME_ALARM:
0072         return "CLOCK_BOOTTIME_ALARM";
0073     case CLOCK_TAI:
0074         return "CLOCK_TAI";
0075     };
0076     return "UNKNOWN_CLOCKID";
0077 }
0078 
0079 /* returns 1 if a <= b, 0 otherwise */
0080 static inline int in_order(struct timespec a, struct timespec b)
0081 {
0082     if (a.tv_sec < b.tv_sec)
0083         return 1;
0084     if (a.tv_sec > b.tv_sec)
0085         return 0;
0086     if (a.tv_nsec > b.tv_nsec)
0087         return 0;
0088     return 1;
0089 }
0090 
0091 struct timespec timespec_add(struct timespec ts, unsigned long long ns)
0092 {
0093     ts.tv_nsec += ns;
0094     while (ts.tv_nsec >= NSEC_PER_SEC) {
0095         ts.tv_nsec -= NSEC_PER_SEC;
0096         ts.tv_sec++;
0097     }
0098     return ts;
0099 }
0100 
0101 int nanosleep_test(int clockid, long long ns)
0102 {
0103     struct timespec now, target, rel;
0104 
0105     /* First check abs time */
0106     if (clock_gettime(clockid, &now))
0107         return UNSUPPORTED;
0108     target = timespec_add(now, ns);
0109 
0110     if (clock_nanosleep(clockid, TIMER_ABSTIME, &target, NULL))
0111         return UNSUPPORTED;
0112     clock_gettime(clockid, &now);
0113 
0114     if (!in_order(target, now))
0115         return -1;
0116 
0117     /* Second check reltime */
0118     clock_gettime(clockid, &now);
0119     rel.tv_sec = 0;
0120     rel.tv_nsec = 0;
0121     rel = timespec_add(rel, ns);
0122     target = timespec_add(now, ns);
0123     clock_nanosleep(clockid, 0, &rel, NULL);
0124     clock_gettime(clockid, &now);
0125 
0126     if (!in_order(target, now))
0127         return -1;
0128     return 0;
0129 }
0130 
0131 int main(int argc, char **argv)
0132 {
0133     long long length;
0134     int clockid, ret;
0135 
0136     ksft_print_header();
0137     ksft_set_plan(NR_CLOCKIDS);
0138 
0139     for (clockid = CLOCK_REALTIME; clockid < NR_CLOCKIDS; clockid++) {
0140 
0141         /* Skip cputime clockids since nanosleep won't increment cputime */
0142         if (clockid == CLOCK_PROCESS_CPUTIME_ID ||
0143                 clockid == CLOCK_THREAD_CPUTIME_ID ||
0144                 clockid == CLOCK_HWSPECIFIC) {
0145             ksft_test_result_skip("%-31s\n", clockstring(clockid));
0146             continue;
0147         }
0148 
0149         fflush(stdout);
0150 
0151         length = 10;
0152         while (length <= (NSEC_PER_SEC * 10)) {
0153             ret = nanosleep_test(clockid, length);
0154             if (ret == UNSUPPORTED) {
0155                 ksft_test_result_skip("%-31s\n", clockstring(clockid));
0156                 goto next;
0157             }
0158             if (ret < 0) {
0159                 ksft_test_result_fail("%-31s\n", clockstring(clockid));
0160                 ksft_exit_fail();
0161             }
0162             length *= 100;
0163         }
0164         ksft_test_result_pass("%-31s\n", clockstring(clockid));
0165 next:
0166         ret = 0;
0167     }
0168     ksft_exit_pass();
0169 }