191 lines · 4.0 KB · C
RawDownload
/* 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 clocksource 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 <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/timex.h>#include <sys/types.h>#include <sys/wait.h>#include <time.h>#include <unistd.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 (WIFEXITED(ret) && WEXITSTATUS(ret))		return WEXITSTATUS(ret);	ret = system("./nanosleep");	return WIFEXITED(ret) ? WEXITSTATUS(ret) : 0;}  char clocksource_list[10][30]; int main(int argc, char **argv){	char orig_clk[512];	int count, i, status, opt;	int do_sanity_check = 1;	int runtime = 60;	pid_t pid; 	/* Process arguments */	while ((opt = getopt(argc, argv, "st:")) != -1) {		switch (opt) {		case 's':			do_sanity_check = 0;			break;		case 't':			runtime = atoi(optarg);			break;		default:			printf("Usage: %s [-s] [-t <secs>]\n", argv[0]);			printf("	-s: skip sanity checks\n");			printf("	-t: Number of seconds to run\n");			exit(-1);		}	} 	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 asynchronously */	if (do_sanity_check) {		for (i = 0; i < count; i++) {			ksft_print_msg("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;			}		}	} 	ksft_print_msg("Running Asynchronous Switching Tests...\n");	pid = fork();	if (!pid)		return run_tests(runtime); 	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); 	/* Print at the end to not mix output with child process */	ksft_print_header();	ksft_set_plan(1);	ksft_test_result(!status, "clocksource-switch\n");	ksft_exit(!status);}