| /* Clocksource change test | |
| * by: john stultz (johnstul@us.ibm.com) | |
| * (C) Copyright IBM 2012 | |
| * Licensed under the GPLv2 | |
| * | |
| * NOTE: This is a meta-test which quickly changes the clocksourc and | |
| * then uses other tests to detect problems. Thus this test requires | |
| * that the inconsistency-check and nanosleep tests be present in the | |
| * same directory it is run from. | |
| * | |
| * To build: | |
| * $ gcc clocksource-switch.c -o clocksource-switch -lrt | |
| * | |
| * This program is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation, either version 2 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| */ | |
| #include <stdio.h> | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <sys/time.h> | |
| #include <sys/timex.h> | |
| #include <time.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #include <string.h> | |
| #include <sys/wait.h> | |
| #ifdef KTEST | |
| #include "../kselftest.h" | |
| #else | |
| static inline int ksft_exit_pass(void) | |
| { | |
| exit(0); | |
| } | |
| static inline int ksft_exit_fail(void) | |
| { | |
| exit(1); | |
| } | |
| #endif | |
| int get_clocksources(char list[][30]) | |
| { | |
| int fd, i; | |
| size_t size; | |
| char buf[512]; | |
| char *head, *tmp; | |
| fd = open("/sys/devices/system/clocksource/clocksource0/available_clocksource", O_RDONLY); | |
| size = read(fd, buf, 512); | |
| close(fd); | |
| for (i = 0; i < 30; i++) | |
| list[i][0] = '\0'; | |
| head = buf; | |
| i = 0; | |
| while (head - buf < size) { | |
| /* Find the next space */ | |
| for (tmp = head; *tmp != ' '; tmp++) { | |
| if (*tmp == '\n') | |
| break; | |
| if (*tmp == '\0') | |
| break; | |
| } | |
| *tmp = '\0'; | |
| strcpy(list[i], head); | |
| head = tmp + 1; | |
| i++; | |
| } | |
| return i-1; | |
| } | |
| int get_cur_clocksource(char *buf, size_t size) | |
| { | |
| int fd; | |
| fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_RDONLY); | |
| size = read(fd, buf, size); | |
| return 0; | |
| } | |
| int change_clocksource(char *clocksource) | |
| { | |
| int fd; | |
| ssize_t size; | |
| fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY); | |
| if (fd < 0) | |
| return -1; | |
| size = write(fd, clocksource, strlen(clocksource)); | |
| if (size < 0) | |
| return -1; | |
| close(fd); | |
| return 0; | |
| } | |
| int run_tests(int secs) | |
| { | |
| int ret; | |
| char buf[255]; | |
| sprintf(buf, "./inconsistency-check -t %i", secs); | |
| ret = system(buf); | |
| if (ret) | |
| return ret; | |
| ret = system("./nanosleep"); | |
| return ret; | |
| } | |
| char clocksource_list[10][30]; | |
| int main(int argv, char **argc) | |
| { | |
| char orig_clk[512]; | |
| int count, i, status; | |
| pid_t pid; | |
| get_cur_clocksource(orig_clk, 512); | |
| count = get_clocksources(clocksource_list); | |
| if (change_clocksource(clocksource_list[0])) { | |
| printf("Error: You probably need to run this as root\n"); | |
| return -1; | |
| } | |
| /* Check everything is sane before we start switching asyncrhonously */ | |
| for (i = 0; i < count; i++) { | |
| printf("Validating clocksource %s\n", clocksource_list[i]); | |
| if (change_clocksource(clocksource_list[i])) { | |
| status = -1; | |
| goto out; | |
| } | |
| if (run_tests(5)) { | |
| status = -1; | |
| goto out; | |
| } | |
| } | |
| printf("Running Asyncrhonous Switching Tests...\n"); | |
| pid = fork(); | |
| if (!pid) | |
| return run_tests(60); | |
| while (pid != waitpid(pid, &status, WNOHANG)) | |
| for (i = 0; i < count; i++) | |
| if (change_clocksource(clocksource_list[i])) { | |
| status = -1; | |
| goto out; | |
| } | |
| out: | |
| change_clocksource(orig_clk); | |
| if (status) | |
| return ksft_exit_fail(); | |
| return ksft_exit_pass(); | |
| } |