1 | /* Clocksource change test |
2 | * by: john stultz (johnstul@us.ibm.com) |
3 | * (C) Copyright IBM 2012 |
4 | * Licensed under the GPLv2 |
5 | * |
6 | * NOTE: This is a meta-test which quickly changes the clocksource and |
7 | * then uses other tests to detect problems. Thus this test requires |
8 | * that the inconsistency-check and nanosleep tests be present in the |
9 | * same directory it is run from. |
10 | * |
11 | * To build: |
12 | * $ gcc clocksource-switch.c -o clocksource-switch -lrt |
13 | * |
14 | * This program is free software: you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation, either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * This program is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | */ |
24 | |
25 | |
26 | #include <fcntl.h> |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | #include <sys/stat.h> |
31 | #include <sys/time.h> |
32 | #include <sys/timex.h> |
33 | #include <sys/types.h> |
34 | #include <sys/wait.h> |
35 | #include <time.h> |
36 | #include <unistd.h> |
37 | #include "../kselftest.h" |
38 | |
39 | |
40 | int get_clocksources(char list[][30]) |
41 | { |
42 | int fd, i; |
43 | size_t size; |
44 | char buf[512]; |
45 | char *head, *tmp; |
46 | |
47 | fd = open("/sys/devices/system/clocksource/clocksource0/available_clocksource" , O_RDONLY); |
48 | |
49 | size = read(fd, buf, 512); |
50 | |
51 | close(fd); |
52 | |
53 | for (i = 0; i < 10; i++) |
54 | list[i][0] = '\0'; |
55 | |
56 | head = buf; |
57 | i = 0; |
58 | while (head - buf < size) { |
59 | /* Find the next space */ |
60 | for (tmp = head; *tmp != ' '; tmp++) { |
61 | if (*tmp == '\n') |
62 | break; |
63 | if (*tmp == '\0') |
64 | break; |
65 | } |
66 | *tmp = '\0'; |
67 | strcpy(list[i], head); |
68 | head = tmp + 1; |
69 | i++; |
70 | } |
71 | |
72 | return i-1; |
73 | } |
74 | |
75 | int get_cur_clocksource(char *buf, size_t size) |
76 | { |
77 | int fd; |
78 | |
79 | fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource" , O_RDONLY); |
80 | |
81 | size = read(fd, buf, size); |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | int change_clocksource(char *clocksource) |
87 | { |
88 | int fd; |
89 | ssize_t size; |
90 | |
91 | fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource" , O_WRONLY); |
92 | |
93 | if (fd < 0) |
94 | return -1; |
95 | |
96 | size = write(fd, clocksource, strlen(clocksource)); |
97 | |
98 | if (size < 0) |
99 | return -1; |
100 | |
101 | close(fd); |
102 | return 0; |
103 | } |
104 | |
105 | |
106 | int run_tests(int secs) |
107 | { |
108 | int ret; |
109 | char buf[255]; |
110 | |
111 | sprintf(buf, "./inconsistency-check -t %i" , secs); |
112 | ret = system(buf); |
113 | if (WIFEXITED(ret) && WEXITSTATUS(ret)) |
114 | return WEXITSTATUS(ret); |
115 | ret = system("./nanosleep" ); |
116 | return WIFEXITED(ret) ? WEXITSTATUS(ret) : 0; |
117 | } |
118 | |
119 | |
120 | char clocksource_list[10][30]; |
121 | |
122 | int main(int argc, char **argv) |
123 | { |
124 | char orig_clk[512]; |
125 | int count, i, status, opt; |
126 | int do_sanity_check = 1; |
127 | int runtime = 60; |
128 | pid_t pid; |
129 | |
130 | /* Process arguments */ |
131 | while ((opt = getopt(argc, argv, "st:" )) != -1) { |
132 | switch (opt) { |
133 | case 's': |
134 | do_sanity_check = 0; |
135 | break; |
136 | case 't': |
137 | runtime = atoi(optarg); |
138 | break; |
139 | default: |
140 | printf("Usage: %s [-s] [-t <secs>]\n" , argv[0]); |
141 | printf(" -s: skip sanity checks\n" ); |
142 | printf(" -t: Number of seconds to run\n" ); |
143 | exit(-1); |
144 | } |
145 | } |
146 | |
147 | get_cur_clocksource(orig_clk, 512); |
148 | |
149 | count = get_clocksources(list: clocksource_list); |
150 | |
151 | if (change_clocksource(clocksource: clocksource_list[0])) { |
152 | printf("Error: You probably need to run this as root\n" ); |
153 | return -1; |
154 | } |
155 | |
156 | /* Check everything is sane before we start switching asynchronously */ |
157 | if (do_sanity_check) { |
158 | for (i = 0; i < count; i++) { |
159 | printf("Validating clocksource %s\n" , |
160 | clocksource_list[i]); |
161 | if (change_clocksource(clocksource: clocksource_list[i])) { |
162 | status = -1; |
163 | goto out; |
164 | } |
165 | if (run_tests(secs: 5)) { |
166 | status = -1; |
167 | goto out; |
168 | } |
169 | } |
170 | } |
171 | |
172 | printf("Running Asynchronous Switching Tests...\n" ); |
173 | pid = fork(); |
174 | if (!pid) |
175 | return run_tests(secs: runtime); |
176 | |
177 | while (pid != waitpid(pid, &status, WNOHANG)) |
178 | for (i = 0; i < count; i++) |
179 | if (change_clocksource(clocksource: clocksource_list[i])) { |
180 | status = -1; |
181 | goto out; |
182 | } |
183 | out: |
184 | change_clocksource(clocksource: orig_clk); |
185 | |
186 | /* Print at the end to not mix output with child process */ |
187 | ksft_print_header(); |
188 | ksft_set_plan(plan: 1); |
189 | ksft_test_result(!status, "clocksource-switch\n" ); |
190 | ksft_exit(!status); |
191 | } |
192 | |