Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
  3 *
  4 * Licensed under the terms of the GNU GPL License version 2
  5 *
  6 * Selftests for a few posix timers interface.
  7 *
  8 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
  9 */
 10
 11#include <sys/time.h>
 12#include <stdio.h>
 13#include <signal.h>
 14#include <unistd.h>
 15#include <time.h>
 16#include <pthread.h>
 17
 18#include "../kselftest.h"
 19
 20#define DELAY 2
 21#define USECS_PER_SEC 1000000
 22
 23static volatile int done;
 24
 25/* Busy loop in userspace to elapse ITIMER_VIRTUAL */
 26static void user_loop(void)
 27{
 28	while (!done);
 29}
 30
 31/*
 32 * Try to spend as much time as possible in kernelspace
 33 * to elapse ITIMER_PROF.
 34 */
 35static void kernel_loop(void)
 36{
 37	void *addr = sbrk(0);
 38	int err = 0;
 39
 40	while (!done && !err) {
 41		err = brk(addr + 4096);
 42		err |= brk(addr);
 43	}
 44}
 45
 46/*
 47 * Sleep until ITIMER_REAL expiration.
 48 */
 49static void idle_loop(void)
 50{
 51	pause();
 52}
 53
 54static void sig_handler(int nr)
 55{
 56	done = 1;
 57}
 58
 59/*
 60 * Check the expected timer expiration matches the GTOD elapsed delta since
 61 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
 62 */
 63static int check_diff(struct timeval start, struct timeval end)
 64{
 65	long long diff;
 66
 67	diff = end.tv_usec - start.tv_usec;
 68	diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
 69
 70	if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
 71		printf("Diff too high: %lld..", diff);
 72		return -1;
 73	}
 74
 75	return 0;
 76}
 77
 78static int check_itimer(int which)
 79{
 80	int err;
 81	struct timeval start, end;
 82	struct itimerval val = {
 83		.it_value.tv_sec = DELAY,
 84	};
 85
 86	printf("Check itimer ");
 87
 88	if (which == ITIMER_VIRTUAL)
 89		printf("virtual... ");
 90	else if (which == ITIMER_PROF)
 91		printf("prof... ");
 92	else if (which == ITIMER_REAL)
 93		printf("real... ");
 94
 95	fflush(stdout);
 96
 97	done = 0;
 98
 99	if (which == ITIMER_VIRTUAL)
100		signal(SIGVTALRM, sig_handler);
101	else if (which == ITIMER_PROF)
102		signal(SIGPROF, sig_handler);
103	else if (which == ITIMER_REAL)
104		signal(SIGALRM, sig_handler);
105
106	err = gettimeofday(&start, NULL);
107	if (err < 0) {
108		perror("Can't call gettimeofday()\n");
109		return -1;
110	}
111
112	err = setitimer(which, &val, NULL);
113	if (err < 0) {
114		perror("Can't set timer\n");
115		return -1;
116	}
117
118	if (which == ITIMER_VIRTUAL)
119		user_loop();
120	else if (which == ITIMER_PROF)
121		kernel_loop();
122	else if (which == ITIMER_REAL)
123		idle_loop();
124
125	err = gettimeofday(&end, NULL);
126	if (err < 0) {
127		perror("Can't call gettimeofday()\n");
128		return -1;
129	}
130
131	if (!check_diff(start, end))
132		printf("[OK]\n");
133	else
134		printf("[FAIL]\n");
135
136	return 0;
137}
138
139static int check_timer_create(int which)
140{
141	int err;
142	timer_t id;
143	struct timeval start, end;
144	struct itimerspec val = {
145		.it_value.tv_sec = DELAY,
146	};
147
148	printf("Check timer_create() ");
149	if (which == CLOCK_THREAD_CPUTIME_ID) {
150		printf("per thread... ");
151	} else if (which == CLOCK_PROCESS_CPUTIME_ID) {
152		printf("per process... ");
153	}
154	fflush(stdout);
155
156	done = 0;
157	err = timer_create(which, NULL, &id);
158	if (err < 0) {
159		perror("Can't create timer\n");
160		return -1;
161	}
162	signal(SIGALRM, sig_handler);
163
164	err = gettimeofday(&start, NULL);
165	if (err < 0) {
166		perror("Can't call gettimeofday()\n");
167		return -1;
168	}
169
170	err = timer_settime(id, 0, &val, NULL);
171	if (err < 0) {
172		perror("Can't set timer\n");
173		return -1;
174	}
175
176	user_loop();
177
178	err = gettimeofday(&end, NULL);
179	if (err < 0) {
180		perror("Can't call gettimeofday()\n");
181		return -1;
182	}
183
184	if (!check_diff(start, end))
185		printf("[OK]\n");
186	else
187		printf("[FAIL]\n");
188
189	return 0;
190}
191
192int main(int argc, char **argv)
193{
194	printf("Testing posix timers. False negative may happen on CPU execution \n");
195	printf("based timers if other threads run on the CPU...\n");
196
197	if (check_itimer(ITIMER_VIRTUAL) < 0)
198		return ksft_exit_fail();
199
200	if (check_itimer(ITIMER_PROF) < 0)
201		return ksft_exit_fail();
202
203	if (check_itimer(ITIMER_REAL) < 0)
204		return ksft_exit_fail();
205
206	if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
207		return ksft_exit_fail();
208
209	/*
210	 * It's unfortunately hard to reliably test a timer expiration
211	 * on parallel multithread cputime. We could arm it to expire
212	 * on DELAY * nr_threads, with nr_threads busy looping, then wait
213	 * the normal DELAY since the time is elapsing nr_threads faster.
214	 * But for that we need to ensure we have real physical free CPUs
215	 * to ensure true parallelism. So test only one thread until we
216	 * find a better solution.
217	 */
218	if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
219		return ksft_exit_fail();
220
221	return ksft_exit_pass();
222}