Commit 8e63360d authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

selftests/timers/posix-timers: Add a test for exact allocation mode



The exact timer ID allocation mode is used by CRIU to restore timers with a
given ID. Add a test case for it.

It's skipped on older kernels when the prctl() fails.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/all/8734fl2tkx.ffs@tglx
parent ec2d0c04
Loading
Loading
Loading
Loading
+72 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
 */
#define _GNU_SOURCE
#include <sys/prctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdio.h>
@@ -599,14 +600,84 @@ static void check_overrun(int which, const char *name)
			 "check_overrun %s\n", name);
}

#include <sys/syscall.h>

static int do_timer_create(int *id)
{
	return syscall(__NR_timer_create, CLOCK_MONOTONIC, NULL, id);
}

static int do_timer_delete(int id)
{
	return syscall(__NR_timer_delete, id);
}

#ifndef PR_TIMER_CREATE_RESTORE_IDS
# define PR_TIMER_CREATE_RESTORE_IDS		77
# define PR_TIMER_CREATE_RESTORE_IDS_OFF	 0
# define PR_TIMER_CREATE_RESTORE_IDS_ON		 1
# define PR_TIMER_CREATE_RESTORE_IDS_GET	 2
#endif

static void check_timer_create_exact(void)
{
	int id;

	if (prctl(PR_TIMER_CREATE_RESTORE_IDS, PR_TIMER_CREATE_RESTORE_IDS_ON, 0, 0, 0)) {
		switch (errno) {
		case EINVAL:
			ksft_test_result_skip("check timer create exact, not supported\n");
			return;
		default:
			ksft_test_result_skip("check timer create exact, errno = %d\n", errno);
			return;
		}
	}

	if (prctl(PR_TIMER_CREATE_RESTORE_IDS, PR_TIMER_CREATE_RESTORE_IDS_GET, 0, 0, 0) != 1)
		fatal_error(NULL, "prctl(GET) failed\n");

	id = 8;
	if (do_timer_create(&id) < 0)
		fatal_error(NULL, "timer_create()");

	if (do_timer_delete(id))
		fatal_error(NULL, "timer_delete()");

	if (prctl(PR_TIMER_CREATE_RESTORE_IDS, PR_TIMER_CREATE_RESTORE_IDS_OFF, 0, 0, 0))
		fatal_error(NULL, "prctl(OFF)");

	if (prctl(PR_TIMER_CREATE_RESTORE_IDS, PR_TIMER_CREATE_RESTORE_IDS_GET, 0, 0, 0) != 0)
		fatal_error(NULL, "prctl(GET) failed\n");

	if (id != 8) {
		ksft_test_result_fail("check timer create exact %d != 8\n", id);
		return;
	}

	/* Validate that it went back to normal mode and allocates ID 9 */
	if (do_timer_create(&id) < 0)
		fatal_error(NULL, "timer_create()");

	if (do_timer_delete(id))
		fatal_error(NULL, "timer_delete()");

	if (id == 9)
		ksft_test_result_pass("check timer create exact\n");
	else
		ksft_test_result_fail("check timer create exact. Disabling failed.\n");
}

int main(int argc, char **argv)
{
	ksft_print_header();
	ksft_set_plan(18);
	ksft_set_plan(19);

	ksft_print_msg("Testing posix timers. False negative may happen on CPU execution \n");
	ksft_print_msg("based timers if other threads run on the CPU...\n");

	check_timer_create_exact();

	check_itimer(ITIMER_VIRTUAL, "ITIMER_VIRTUAL");
	check_itimer(ITIMER_PROF, "ITIMER_PROF");
	check_itimer(ITIMER_REAL, "ITIMER_REAL");