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(clocksource_list); 150 151 if (change_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_list[i])) { 162 status = -1; 163 goto out; 164 } 165 if (run_tests(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(runtime); 176 177 while (pid != waitpid(pid, &status, WNOHANG)) 178 for (i = 0; i < count; i++) 179 if (change_clocksource(clocksource_list[i])) { 180 status = -1; 181 goto out; 182 } 183 out: 184 change_clocksource(orig_clk); 185 186 /* Print at the end to not mix output with child process */ 187 ksft_print_header(); 188 ksft_set_plan(1); 189 ksft_test_result(!status, "clocksource-switch\n"); 190 ksft_exit(!status); 191 } 192