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 <stdio.h> 27 #include <unistd.h> 28 #include <stdlib.h> 29 #include <sys/time.h> 30 #include <sys/timex.h> 31 #include <time.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <string.h> 36 #include <sys/wait.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 (ret) 114 return ret; 115 ret = system("./nanosleep"); 116 return ret; 117 } 118 119 120 char clocksource_list[10][30]; 121 122 int main(int argv, char **argc) 123 { 124 char orig_clk[512]; 125 int count, i, status; 126 pid_t pid; 127 128 get_cur_clocksource(orig_clk, 512); 129 130 count = get_clocksources(clocksource_list); 131 132 if (change_clocksource(clocksource_list[0])) { 133 printf("Error: You probably need to run this as root\n"); 134 return -1; 135 } 136 137 /* Check everything is sane before we start switching asynchronously */ 138 for (i = 0; i < count; i++) { 139 printf("Validating clocksource %s\n", clocksource_list[i]); 140 if (change_clocksource(clocksource_list[i])) { 141 status = -1; 142 goto out; 143 } 144 if (run_tests(5)) { 145 status = -1; 146 goto out; 147 } 148 } 149 150 151 printf("Running Asynchronous Switching Tests...\n"); 152 pid = fork(); 153 if (!pid) 154 return run_tests(60); 155 156 while (pid != waitpid(pid, &status, WNOHANG)) 157 for (i = 0; i < count; i++) 158 if (change_clocksource(clocksource_list[i])) { 159 status = -1; 160 goto out; 161 } 162 out: 163 change_clocksource(orig_clk); 164 165 if (status) 166 return ksft_exit_fail(); 167 return ksft_exit_pass(); 168 } 169