18c2ecf20Sopenharmony_ci/* Clocksource change test
28c2ecf20Sopenharmony_ci *		by: john stultz (johnstul@us.ibm.com)
38c2ecf20Sopenharmony_ci *		(C) Copyright IBM 2012
48c2ecf20Sopenharmony_ci *		Licensed under the GPLv2
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *  NOTE: This is a meta-test which quickly changes the clocksourc and
78c2ecf20Sopenharmony_ci *  then uses other tests to detect problems. Thus this test requires
88c2ecf20Sopenharmony_ci *  that the inconsistency-check and nanosleep tests be present in the
98c2ecf20Sopenharmony_ci *  same directory it is run from.
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  To build:
128c2ecf20Sopenharmony_ci *	$ gcc clocksource-switch.c -o clocksource-switch -lrt
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *   This program is free software: you can redistribute it and/or modify
158c2ecf20Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
168c2ecf20Sopenharmony_ci *   the Free Software Foundation, either version 2 of the License, or
178c2ecf20Sopenharmony_ci *   (at your option) any later version.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
208c2ecf20Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
218c2ecf20Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
228c2ecf20Sopenharmony_ci *   GNU General Public License for more details.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <stdio.h>
278c2ecf20Sopenharmony_ci#include <unistd.h>
288c2ecf20Sopenharmony_ci#include <stdlib.h>
298c2ecf20Sopenharmony_ci#include <sys/time.h>
308c2ecf20Sopenharmony_ci#include <sys/timex.h>
318c2ecf20Sopenharmony_ci#include <time.h>
328c2ecf20Sopenharmony_ci#include <sys/types.h>
338c2ecf20Sopenharmony_ci#include <sys/stat.h>
348c2ecf20Sopenharmony_ci#include <fcntl.h>
358c2ecf20Sopenharmony_ci#include <string.h>
368c2ecf20Sopenharmony_ci#include <sys/wait.h>
378c2ecf20Sopenharmony_ci#include "../kselftest.h"
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciint get_clocksources(char list[][30])
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	int fd, i;
438c2ecf20Sopenharmony_ci	size_t size;
448c2ecf20Sopenharmony_ci	char buf[512];
458c2ecf20Sopenharmony_ci	char *head, *tmp;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	fd = open("/sys/devices/system/clocksource/clocksource0/available_clocksource", O_RDONLY);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	size = read(fd, buf, 512);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	close(fd);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++)
548c2ecf20Sopenharmony_ci		list[i][0] = '\0';
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	head = buf;
578c2ecf20Sopenharmony_ci	i = 0;
588c2ecf20Sopenharmony_ci	while (head - buf < size) {
598c2ecf20Sopenharmony_ci		/* Find the next space */
608c2ecf20Sopenharmony_ci		for (tmp = head; *tmp != ' '; tmp++) {
618c2ecf20Sopenharmony_ci			if (*tmp == '\n')
628c2ecf20Sopenharmony_ci				break;
638c2ecf20Sopenharmony_ci			if (*tmp == '\0')
648c2ecf20Sopenharmony_ci				break;
658c2ecf20Sopenharmony_ci		}
668c2ecf20Sopenharmony_ci		*tmp = '\0';
678c2ecf20Sopenharmony_ci		strcpy(list[i], head);
688c2ecf20Sopenharmony_ci		head = tmp + 1;
698c2ecf20Sopenharmony_ci		i++;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return i-1;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciint get_cur_clocksource(char *buf, size_t size)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int fd;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_RDONLY);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	size = read(fd, buf, size);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return 0;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciint change_clocksource(char *clocksource)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int fd;
898c2ecf20Sopenharmony_ci	ssize_t size;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	if (fd < 0)
948c2ecf20Sopenharmony_ci		return -1;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	size = write(fd, clocksource, strlen(clocksource));
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (size < 0)
998c2ecf20Sopenharmony_ci		return -1;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	close(fd);
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciint run_tests(int secs)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	int ret;
1098c2ecf20Sopenharmony_ci	char buf[255];
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	sprintf(buf, "./inconsistency-check -t %i", secs);
1128c2ecf20Sopenharmony_ci	ret = system(buf);
1138c2ecf20Sopenharmony_ci	if (WIFEXITED(ret) && WEXITSTATUS(ret))
1148c2ecf20Sopenharmony_ci		return WEXITSTATUS(ret);
1158c2ecf20Sopenharmony_ci	ret = system("./nanosleep");
1168c2ecf20Sopenharmony_ci	return WIFEXITED(ret) ? WEXITSTATUS(ret) : 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cichar clocksource_list[10][30];
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciint main(int argv, char **argc)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	char orig_clk[512];
1258c2ecf20Sopenharmony_ci	int count, i, status;
1268c2ecf20Sopenharmony_ci	pid_t pid;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	get_cur_clocksource(orig_clk, 512);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	count = get_clocksources(clocksource_list);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (change_clocksource(clocksource_list[0])) {
1338c2ecf20Sopenharmony_ci		printf("Error: You probably need to run this as root\n");
1348c2ecf20Sopenharmony_ci		return -1;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	/* Check everything is sane before we start switching asyncrhonously */
1388c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++) {
1398c2ecf20Sopenharmony_ci		printf("Validating clocksource %s\n", clocksource_list[i]);
1408c2ecf20Sopenharmony_ci		if (change_clocksource(clocksource_list[i])) {
1418c2ecf20Sopenharmony_ci			status = -1;
1428c2ecf20Sopenharmony_ci			goto out;
1438c2ecf20Sopenharmony_ci		}
1448c2ecf20Sopenharmony_ci		if (run_tests(5)) {
1458c2ecf20Sopenharmony_ci			status = -1;
1468c2ecf20Sopenharmony_ci			goto out;
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	printf("Running Asynchronous Switching Tests...\n");
1528c2ecf20Sopenharmony_ci	pid = fork();
1538c2ecf20Sopenharmony_ci	if (!pid)
1548c2ecf20Sopenharmony_ci		return run_tests(60);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	while (pid != waitpid(pid, &status, WNOHANG))
1578c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++)
1588c2ecf20Sopenharmony_ci			if (change_clocksource(clocksource_list[i])) {
1598c2ecf20Sopenharmony_ci				status = -1;
1608c2ecf20Sopenharmony_ci				goto out;
1618c2ecf20Sopenharmony_ci			}
1628c2ecf20Sopenharmony_ciout:
1638c2ecf20Sopenharmony_ci	change_clocksource(orig_clk);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	if (status)
1668c2ecf20Sopenharmony_ci		return ksft_exit_fail();
1678c2ecf20Sopenharmony_ci	return ksft_exit_pass();
1688c2ecf20Sopenharmony_ci}
169