/* 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> #include "../kselftest.h" 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 < 10; 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 Asynchronous 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(); }