brintos

brintos / linux-shallow public Read only

0
0
Text · 15.7 KiB · ddb1ceb Raw
643 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>4 *5 * Selftests for a few posix timers interface.6 *7 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>8 */9#define _GNU_SOURCE10#include <sys/time.h>11#include <sys/types.h>12#include <stdio.h>13#include <signal.h>14#include <stdint.h>15#include <string.h>16#include <unistd.h>17#include <time.h>18#include <pthread.h>19 20#include "../kselftest.h"21 22#define DELAY 223#define USECS_PER_SEC 100000024#define NSECS_PER_SEC 100000000025 26static void __fatal_error(const char *test, const char *name, const char *what)27{28	char buf[64];29	char *ret_str = NULL;30 31	ret_str = strerror_r(errno, buf, sizeof(buf));32 33	if (name && strlen(name) && ret_str)34		ksft_exit_fail_msg("%s %s %s %s\n", test, name, what, ret_str);35	else if (ret_str)36		ksft_exit_fail_msg("%s %s %s\n", test, what, ret_str);37	else38		ksft_exit_fail_msg("%s %s\n", test, what);39 40}41 42#define fatal_error(name, what)	__fatal_error(__func__, name, what)43 44static volatile int done;45 46/* Busy loop in userspace to elapse ITIMER_VIRTUAL */47static void user_loop(void)48{49	while (!done);50}51 52/*53 * Try to spend as much time as possible in kernelspace54 * to elapse ITIMER_PROF.55 */56static void kernel_loop(void)57{58	void *addr = sbrk(0);59	int err = 0;60 61	while (!done && !err) {62		err = brk(addr + 4096);63		err |= brk(addr);64	}65}66 67/*68 * Sleep until ITIMER_REAL expiration.69 */70static void idle_loop(void)71{72	pause();73}74 75static void sig_handler(int nr)76{77	done = 1;78}79 80/*81 * Check the expected timer expiration matches the GTOD elapsed delta since82 * we armed the timer. Keep a 0.5 sec error margin due to various jitter.83 */84static int check_diff(struct timeval start, struct timeval end)85{86	long long diff;87 88	diff = end.tv_usec - start.tv_usec;89	diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;90 91	if (llabs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {92		printf("Diff too high: %lld..", diff);93		return -1;94	}95 96	return 0;97}98 99static void check_itimer(int which, const char *name)100{101	struct timeval start, end;102	struct itimerval val = {103		.it_value.tv_sec = DELAY,104	};105 106	done = 0;107 108	if (which == ITIMER_VIRTUAL)109		signal(SIGVTALRM, sig_handler);110	else if (which == ITIMER_PROF)111		signal(SIGPROF, sig_handler);112	else if (which == ITIMER_REAL)113		signal(SIGALRM, sig_handler);114 115	if (gettimeofday(&start, NULL) < 0)116		fatal_error(name, "gettimeofday()");117 118	if (setitimer(which, &val, NULL) < 0)119		fatal_error(name, "setitimer()");120 121	if (which == ITIMER_VIRTUAL)122		user_loop();123	else if (which == ITIMER_PROF)124		kernel_loop();125	else if (which == ITIMER_REAL)126		idle_loop();127 128	if (gettimeofday(&end, NULL) < 0)129		fatal_error(name, "gettimeofday()");130 131	ksft_test_result(check_diff(start, end) == 0, "%s\n", name);132}133 134static void check_timer_create(int which, const char *name)135{136	struct timeval start, end;137	struct itimerspec val = {138		.it_value.tv_sec = DELAY,139	};140	timer_t id;141 142	done = 0;143 144	if (timer_create(which, NULL, &id) < 0)145		fatal_error(name, "timer_create()");146 147	if (signal(SIGALRM, sig_handler) == SIG_ERR)148		fatal_error(name, "signal()");149 150	if (gettimeofday(&start, NULL) < 0)151		fatal_error(name, "gettimeofday()");152 153	if (timer_settime(id, 0, &val, NULL) < 0)154		fatal_error(name, "timer_settime()");155 156	user_loop();157 158	if (gettimeofday(&end, NULL) < 0)159		fatal_error(name, "gettimeofday()");160 161	ksft_test_result(check_diff(start, end) == 0,162			 "timer_create() per %s\n", name);163}164 165static pthread_t ctd_thread;166static volatile int ctd_count, ctd_failed;167 168static void ctd_sighandler(int sig)169{170	if (pthread_self() != ctd_thread)171		ctd_failed = 1;172	ctd_count--;173}174 175static void *ctd_thread_func(void *arg)176{177	struct itimerspec val = {178		.it_value.tv_sec = 0,179		.it_value.tv_nsec = 1000 * 1000,180		.it_interval.tv_sec = 0,181		.it_interval.tv_nsec = 1000 * 1000,182	};183	timer_t id;184 185	/* 1/10 seconds to ensure the leader sleeps */186	usleep(10000);187 188	ctd_count = 100;189	if (timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id))190		fatal_error(NULL, "timer_create()");191	if (timer_settime(id, 0, &val, NULL))192		fatal_error(NULL, "timer_settime()");193	while (ctd_count > 0 && !ctd_failed)194		;195 196	if (timer_delete(id))197		fatal_error(NULL, "timer_delete()");198 199	return NULL;200}201 202/*203 * Test that only the running thread receives the timer signal.204 */205static void check_timer_distribution(void)206{207	if (signal(SIGALRM, ctd_sighandler) == SIG_ERR)208		fatal_error(NULL, "signal()");209 210	if (pthread_create(&ctd_thread, NULL, ctd_thread_func, NULL))211		fatal_error(NULL, "pthread_create()");212 213	if (pthread_join(ctd_thread, NULL))214		fatal_error(NULL, "pthread_join()");215 216	if (!ctd_failed)217		ksft_test_result_pass("check signal distribution\n");218	else if (ksft_min_kernel_version(6, 3))219		ksft_test_result_fail("check signal distribution\n");220	else221		ksft_test_result_skip("check signal distribution (old kernel)\n");222}223 224struct tmrsig {225	int	signals;226	int	overruns;227};228 229static void siginfo_handler(int sig, siginfo_t *si, void *uc)230{231	struct tmrsig *tsig = si ? si->si_ptr : NULL;232 233	if (tsig) {234		tsig->signals++;235		tsig->overruns += si->si_overrun;236	}237}238 239static void *ignore_thread(void *arg)240{241	unsigned int *tid = arg;242	sigset_t set;243 244	sigemptyset(&set);245	sigaddset(&set, SIGUSR1);246	if (sigprocmask(SIG_BLOCK, &set, NULL))247		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");248 249	*tid = gettid();250	sleep(100);251 252	if (sigprocmask(SIG_UNBLOCK, &set, NULL))253		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");254	return NULL;255}256 257static void check_sig_ign(int thread)258{259	struct tmrsig tsig = { };260	struct itimerspec its;261	unsigned int tid = 0;262	struct sigaction sa;263	struct sigevent sev;264	pthread_t pthread;265	timer_t timerid;266	sigset_t set;267 268	if (thread) {269		if (pthread_create(&pthread, NULL, ignore_thread, &tid))270			fatal_error(NULL, "pthread_create()");271		sleep(1);272	}273 274	sa.sa_flags = SA_SIGINFO;275	sa.sa_sigaction = siginfo_handler;276	sigemptyset(&sa.sa_mask);277	if (sigaction(SIGUSR1, &sa, NULL))278		fatal_error(NULL, "sigaction()");279 280	/* Block the signal */281	sigemptyset(&set);282	sigaddset(&set, SIGUSR1);283	if (sigprocmask(SIG_BLOCK, &set, NULL))284		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");285 286	memset(&sev, 0, sizeof(sev));287	sev.sigev_notify = SIGEV_SIGNAL;288	sev.sigev_signo = SIGUSR1;289	sev.sigev_value.sival_ptr = &tsig;290	if (thread) {291		sev.sigev_notify = SIGEV_THREAD_ID;292		sev._sigev_un._tid = tid;293	}294 295	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))296		fatal_error(NULL, "timer_create()");297 298	/* Start the timer to expire in 100ms and 100ms intervals */299	its.it_value.tv_sec = 0;300	its.it_value.tv_nsec = 100000000;301	its.it_interval.tv_sec = 0;302	its.it_interval.tv_nsec = 100000000;303	timer_settime(timerid, 0, &its, NULL);304 305	sleep(1);306 307	/* Set the signal to be ignored */308	if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)309		fatal_error(NULL, "signal(SIG_IGN)");310 311	sleep(1);312 313	if (thread) {314		/* Stop the thread first. No signal should be delivered to it */315		if (pthread_cancel(pthread))316			fatal_error(NULL, "pthread_cancel()");317		if (pthread_join(pthread, NULL))318			fatal_error(NULL, "pthread_join()");319	}320 321	/* Restore the handler */322	if (sigaction(SIGUSR1, &sa, NULL))323		fatal_error(NULL, "sigaction()");324 325	sleep(1);326 327	/* Unblock it, which should deliver the signal in the !thread case*/328	if (sigprocmask(SIG_UNBLOCK, &set, NULL))329		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");330 331	if (timer_delete(timerid))332		fatal_error(NULL, "timer_delete()");333 334	if (!thread) {335		ksft_test_result(tsig.signals == 1 && tsig.overruns == 29,336				 "check_sig_ign SIGEV_SIGNAL\n");337	} else {338		ksft_test_result(tsig.signals == 0 && tsig.overruns == 0,339				 "check_sig_ign SIGEV_THREAD_ID\n");340	}341}342 343static void check_rearm(void)344{345	struct tmrsig tsig = { };346	struct itimerspec its;347	struct sigaction sa;348	struct sigevent sev;349	timer_t timerid;350	sigset_t set;351 352	sa.sa_flags = SA_SIGINFO;353	sa.sa_sigaction = siginfo_handler;354	sigemptyset(&sa.sa_mask);355	if (sigaction(SIGUSR1, &sa, NULL))356		fatal_error(NULL, "sigaction()");357 358	/* Block the signal */359	sigemptyset(&set);360	sigaddset(&set, SIGUSR1);361	if (sigprocmask(SIG_BLOCK, &set, NULL))362		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");363 364	memset(&sev, 0, sizeof(sev));365	sev.sigev_notify = SIGEV_SIGNAL;366	sev.sigev_signo = SIGUSR1;367	sev.sigev_value.sival_ptr = &tsig;368	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))369		fatal_error(NULL, "timer_create()");370 371	/* Start the timer to expire in 100ms and 100ms intervals */372	its.it_value.tv_sec = 0;373	its.it_value.tv_nsec = 100000000;374	its.it_interval.tv_sec = 0;375	its.it_interval.tv_nsec = 100000000;376	if (timer_settime(timerid, 0, &its, NULL))377		fatal_error(NULL, "timer_settime()");378 379	sleep(1);380 381	/* Reprogram the timer to single shot */382	its.it_value.tv_sec = 10;383	its.it_value.tv_nsec = 0;384	its.it_interval.tv_sec = 0;385	its.it_interval.tv_nsec = 0;386	if (timer_settime(timerid, 0, &its, NULL))387		fatal_error(NULL, "timer_settime()");388 389	/* Unblock it, which should not deliver a signal */390	if (sigprocmask(SIG_UNBLOCK, &set, NULL))391		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");392 393	if (timer_delete(timerid))394		fatal_error(NULL, "timer_delete()");395 396	ksft_test_result(!tsig.signals, "check_rearm\n");397}398 399static void check_delete(void)400{401	struct tmrsig tsig = { };402	struct itimerspec its;403	struct sigaction sa;404	struct sigevent sev;405	timer_t timerid;406	sigset_t set;407 408	sa.sa_flags = SA_SIGINFO;409	sa.sa_sigaction = siginfo_handler;410	sigemptyset(&sa.sa_mask);411	if (sigaction(SIGUSR1, &sa, NULL))412		fatal_error(NULL, "sigaction()");413 414	/* Block the signal */415	sigemptyset(&set);416	sigaddset(&set, SIGUSR1);417	if (sigprocmask(SIG_BLOCK, &set, NULL))418		fatal_error(NULL, "sigprocmask(SIG_BLOCK)");419 420	memset(&sev, 0, sizeof(sev));421	sev.sigev_notify = SIGEV_SIGNAL;422	sev.sigev_signo = SIGUSR1;423	sev.sigev_value.sival_ptr = &tsig;424	if (timer_create(CLOCK_MONOTONIC, &sev, &timerid))425		fatal_error(NULL, "timer_create()");426 427	/* Start the timer to expire in 100ms and 100ms intervals */428	its.it_value.tv_sec = 0;429	its.it_value.tv_nsec = 100000000;430	its.it_interval.tv_sec = 0;431	its.it_interval.tv_nsec = 100000000;432	if (timer_settime(timerid, 0, &its, NULL))433		fatal_error(NULL, "timer_settime()");434 435	sleep(1);436 437	if (timer_delete(timerid))438		fatal_error(NULL, "timer_delete()");439 440	/* Unblock it, which should not deliver a signal */441	if (sigprocmask(SIG_UNBLOCK, &set, NULL))442		fatal_error(NULL, "sigprocmask(SIG_UNBLOCK)");443 444	ksft_test_result(!tsig.signals, "check_delete\n");445}446 447static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2)448{449	int64_t diff;450 451	diff = NSECS_PER_SEC * (int64_t)((int) t1.tv_sec - (int) t2.tv_sec);452	diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);453	return diff;454}455 456static void check_sigev_none(int which, const char *name)457{458	struct timespec start, now;459	struct itimerspec its;460	struct sigevent sev;461	timer_t timerid;462 463	memset(&sev, 0, sizeof(sev));464	sev.sigev_notify = SIGEV_NONE;465 466	if (timer_create(which, &sev, &timerid))467		fatal_error(name, "timer_create()");468 469	/* Start the timer to expire in 100ms and 100ms intervals */470	its.it_value.tv_sec = 0;471	its.it_value.tv_nsec = 100000000;472	its.it_interval.tv_sec = 0;473	its.it_interval.tv_nsec = 100000000;474	timer_settime(timerid, 0, &its, NULL);475 476	if (clock_gettime(which, &start))477		fatal_error(name, "clock_gettime()");478 479	do {480		if (clock_gettime(which, &now))481			fatal_error(name, "clock_gettime()");482	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);483 484	if (timer_gettime(timerid, &its))485		fatal_error(name, "timer_gettime()");486 487	if (timer_delete(timerid))488		fatal_error(name, "timer_delete()");489 490	ksft_test_result(its.it_value.tv_sec || its.it_value.tv_nsec,491			 "check_sigev_none %s\n", name);492}493 494static void check_gettime(int which, const char *name)495{496	struct itimerspec its, prev;497	struct timespec start, now;498	struct sigevent sev;499	timer_t timerid;500	int wraps = 0;501	sigset_t set;502 503	/* Block the signal */504	sigemptyset(&set);505	sigaddset(&set, SIGUSR1);506	if (sigprocmask(SIG_BLOCK, &set, NULL))507		fatal_error(name, "sigprocmask(SIG_BLOCK)");508 509	memset(&sev, 0, sizeof(sev));510	sev.sigev_notify = SIGEV_SIGNAL;511	sev.sigev_signo = SIGUSR1;512 513	if (timer_create(which, &sev, &timerid))514		fatal_error(name, "timer_create()");515 516	/* Start the timer to expire in 100ms and 100ms intervals */517	its.it_value.tv_sec = 0;518	its.it_value.tv_nsec = 100000000;519	its.it_interval.tv_sec = 0;520	its.it_interval.tv_nsec = 100000000;521	if (timer_settime(timerid, 0, &its, NULL))522		fatal_error(name, "timer_settime()");523 524	if (timer_gettime(timerid, &prev))525		fatal_error(name, "timer_gettime()");526 527	if (clock_gettime(which, &start))528		fatal_error(name, "clock_gettime()");529 530	do {531		if (clock_gettime(which, &now))532			fatal_error(name, "clock_gettime()");533		if (timer_gettime(timerid, &its))534			fatal_error(name, "timer_gettime()");535		if (its.it_value.tv_nsec > prev.it_value.tv_nsec)536			wraps++;537		prev = its;538 539	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);540 541	if (timer_delete(timerid))542		fatal_error(name, "timer_delete()");543 544	ksft_test_result(wraps > 1, "check_gettime %s\n", name);545}546 547static void check_overrun(int which, const char *name)548{549	struct timespec start, now;550	struct tmrsig tsig = { };551	struct itimerspec its;552	struct sigaction sa;553	struct sigevent sev;554	timer_t timerid;555	sigset_t set;556 557	sa.sa_flags = SA_SIGINFO;558	sa.sa_sigaction = siginfo_handler;559	sigemptyset(&sa.sa_mask);560	if (sigaction(SIGUSR1, &sa, NULL))561		fatal_error(name, "sigaction()");562 563	/* Block the signal */564	sigemptyset(&set);565	sigaddset(&set, SIGUSR1);566	if (sigprocmask(SIG_BLOCK, &set, NULL))567		fatal_error(name, "sigprocmask(SIG_BLOCK)");568 569	memset(&sev, 0, sizeof(sev));570	sev.sigev_notify = SIGEV_SIGNAL;571	sev.sigev_signo = SIGUSR1;572	sev.sigev_value.sival_ptr = &tsig;573	if (timer_create(which, &sev, &timerid))574		fatal_error(name, "timer_create()");575 576	/* Start the timer to expire in 100ms and 100ms intervals */577	its.it_value.tv_sec = 0;578	its.it_value.tv_nsec = 100000000;579	its.it_interval.tv_sec = 0;580	its.it_interval.tv_nsec = 100000000;581	if (timer_settime(timerid, 0, &its, NULL))582		fatal_error(name, "timer_settime()");583 584	if (clock_gettime(which, &start))585		fatal_error(name, "clock_gettime()");586 587	do {588		if (clock_gettime(which, &now))589			fatal_error(name, "clock_gettime()");590	} while (calcdiff_ns(now, start) < NSECS_PER_SEC);591 592	/* Unblock it, which should deliver a signal */593	if (sigprocmask(SIG_UNBLOCK, &set, NULL))594		fatal_error(name, "sigprocmask(SIG_UNBLOCK)");595 596	if (timer_delete(timerid))597		fatal_error(name, "timer_delete()");598 599	ksft_test_result(tsig.signals == 1 && tsig.overruns == 9,600			 "check_overrun %s\n", name);601}602 603int main(int argc, char **argv)604{605	ksft_print_header();606	ksft_set_plan(18);607 608	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");609	ksft_print_msg("based timers if other threads run on the CPU...\n");610 611	check_itimer(ITIMER_VIRTUAL, "ITIMER_VIRTUAL");612	check_itimer(ITIMER_PROF, "ITIMER_PROF");613	check_itimer(ITIMER_REAL, "ITIMER_REAL");614	check_timer_create(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");615 616	/*617	 * It's unfortunately hard to reliably test a timer expiration618	 * on parallel multithread cputime. We could arm it to expire619	 * on DELAY * nr_threads, with nr_threads busy looping, then wait620	 * the normal DELAY since the time is elapsing nr_threads faster.621	 * But for that we need to ensure we have real physical free CPUs622	 * to ensure true parallelism. So test only one thread until we623	 * find a better solution.624	 */625	check_timer_create(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");626	check_timer_distribution();627 628	check_sig_ign(0);629	check_sig_ign(1);630	check_rearm();631	check_delete();632	check_sigev_none(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");633	check_sigev_none(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");634	check_gettime(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");635	check_gettime(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");636	check_gettime(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");637	check_overrun(CLOCK_MONOTONIC, "CLOCK_MONOTONIC");638	check_overrun(CLOCK_PROCESS_CPUTIME_ID, "CLOCK_PROCESS_CPUTIME_ID");639	check_overrun(CLOCK_THREAD_CPUTIME_ID, "CLOCK_THREAD_CPUTIME_ID");640 641	ksft_finished();642}643