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 clocksourc 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#ifdef KTEST 38#include "../kselftest.h" 39#else 40static inline int ksft_exit_pass(void) 41{ 42 exit(0); 43} 44static inline int ksft_exit_fail(void) 45{ 46 exit(1); 47} 48#endif 49 50 51int get_clocksources(char list[][30]) 52{ 53 int fd, i; 54 size_t size; 55 char buf[512]; 56 char *head, *tmp; 57 58 fd = open("/sys/devices/system/clocksource/clocksource0/available_clocksource", O_RDONLY); 59 60 size = read(fd, buf, 512); 61 62 close(fd); 63 64 for (i = 0; i < 30; i++) 65 list[i][0] = '\0'; 66 67 head = buf; 68 i = 0; 69 while (head - buf < size) { 70 /* Find the next space */ 71 for (tmp = head; *tmp != ' '; tmp++) { 72 if (*tmp == '\n') 73 break; 74 if (*tmp == '\0') 75 break; 76 } 77 *tmp = '\0'; 78 strcpy(list[i], head); 79 head = tmp + 1; 80 i++; 81 } 82 83 return i-1; 84} 85 86int get_cur_clocksource(char *buf, size_t size) 87{ 88 int fd; 89 90 fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_RDONLY); 91 92 size = read(fd, buf, size); 93 94 return 0; 95} 96 97int change_clocksource(char *clocksource) 98{ 99 int fd; 100 size_t size; 101 102 fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY); 103 104 if (fd < 0) 105 return -1; 106 107 size = write(fd, clocksource, strlen(clocksource)); 108 109 if (size < 0) 110 return -1; 111 112 close(fd); 113 return 0; 114} 115 116 117int run_tests(int secs) 118{ 119 int ret; 120 char buf[255]; 121 122 sprintf(buf, "./inconsistency-check -t %i", secs); 123 ret = system(buf); 124 if (ret) 125 return ret; 126 ret = system("./nanosleep"); 127 return ret; 128} 129 130 131char clocksource_list[10][30]; 132 133int main(int argv, char **argc) 134{ 135 char orig_clk[512]; 136 int count, i, status; 137 pid_t pid; 138 139 get_cur_clocksource(orig_clk, 512); 140 141 count = get_clocksources(clocksource_list); 142 143 if (change_clocksource(clocksource_list[0])) { 144 printf("Error: You probably need to run this as root\n"); 145 return -1; 146 } 147 148 /* Check everything is sane before we start switching asyncrhonously */ 149 for (i = 0; i < count; i++) { 150 printf("Validating clocksource %s\n", clocksource_list[i]); 151 if (change_clocksource(clocksource_list[i])) { 152 status = -1; 153 goto out; 154 } 155 if (run_tests(5)) { 156 status = -1; 157 goto out; 158 } 159 } 160 161 162 printf("Running Asyncrhonous Switching Tests...\n"); 163 pid = fork(); 164 if (!pid) 165 return run_tests(60); 166 167 while (pid != waitpid(pid, &status, WNOHANG)) 168 for (i = 0; i < count; i++) 169 if (change_clocksource(clocksource_list[i])) { 170 status = -1; 171 goto out; 172 } 173out: 174 change_clocksource(orig_clk); 175 176 if (status) 177 return ksft_exit_fail(); 178 return ksft_exit_pass(); 179} 180