[LTP] [PATCH v4 2/2] Add clock_settime04 test

Cyril Hrubis chrubis@suse.cz
Fri Aug 1 14:41:14 CEST 2025


Hi!
> > Here as well, SAFE_CLOCK_GETTIME() uses struct timespec as defined by
> > libc, so we have to either use syscall that corresponds to the
> > begin->type (tv->clock_gettime), or covert the value from
> > SAFE_CLOCK_GETTIME() into the right type. I guess that it would look
> > like:
> 
> Why not just going back to the original idea in v1, where we are using 
> the clock_gettime/settime corresponding to the right libc?

Actually the v4 was quite close to what I had in my mind, the corrected
code looks like:

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2025 Andrea Cervesato <andrea.cervesato@suse.com>
 */

/*\
 * Verify that changing the value of the CLOCK_REALTIME clock via
 * clock_settime() shall have no effect on a thread that is blocked on
 * absolute/relative clock_nanosleep().
 */

#include "tst_test.h"
#include "tst_timer.h"
#include "tst_safe_clocks.h"
#include "time64_variants.h"

#define SEC_TO_US(x)     (x * 1000 * 1000)

#define CHILD_SLEEP_US SEC_TO_US(5)
#define PARENT_SLEEP_S 2
#define DELTA_US SEC_TO_US(1)

static struct tst_ts *sleep_child;

static struct time64_variants variants[] = {
	{
		.clock_nanosleep = libc_clock_nanosleep,
		.ts_type = TST_LIBC_TIMESPEC,
		.desc = "vDSO or syscall with libc spec"
	},

#if (__NR_clock_nanosleep != __LTP__NR_INVALID_SYSCALL)
	{
		.clock_nanosleep = sys_clock_nanosleep,
		.ts_type = TST_KERN_OLD_TIMESPEC,
		.desc = "syscall with old kernel spec"
	},
#endif

#if (__NR_clock_nanosleep_time64 != __LTP__NR_INVALID_SYSCALL)
	{
		.clock_nanosleep = sys_clock_nanosleep64,
		.ts_type = TST_KERN_TIMESPEC,
		.desc = "syscall time64 with kernel spec"
	},
#endif
};

static void child_nanosleep(struct time64_variants *tv, const int flags)
{
	long long delta;
	struct timespec begin, end;

	SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &begin);

	if (flags & TIMER_ABSTIME) {
		tst_res(TINFO, "Using absolute time sleep");

		tst_ts_set_sec(sleep_child, begin.tv_sec);
		tst_ts_set_nsec(sleep_child, begin.tv_nsec);

		*sleep_child = tst_ts_add_us(*sleep_child, CHILD_SLEEP_US);
	} else {
		tst_res(TINFO, "Using relative time sleep");

		*sleep_child = tst_ts_from_us(sleep_child->type, CHILD_SLEEP_US);
	}

	TEST(tv->clock_nanosleep(CLOCK_REALTIME, flags, tst_ts_get(sleep_child), NULL));
	if (TST_RET)
		tst_brk(TBROK | TERRNO, "clock_nanosleep() error");

	SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &end);

	if (tst_timespec_lt(end, begin)) {
		tst_res(TFAIL, "clock_settime() didn't sleep enough. "
			"begin: %lld ms >= end: %lld ms",
			tst_timespec_to_ms(begin),
			tst_timespec_to_ms(end));
		return;
	}

	delta = tst_timespec_abs_diff_us(begin, end);
	if (!(flags & TIMER_ABSTIME))
		delta -= CHILD_SLEEP_US;

	if (delta > DELTA_US) {
		tst_res(TFAIL, "parent clock_settime() affected child sleep. "
			"begin: %lld ms, end: %lld ms",
			tst_timespec_to_ms(begin),
			tst_timespec_to_ms(end));
		return;
	}

	tst_res(TPASS, "parent clock_settime() didn't affect child sleep "
		"(delta time: %lld us)", delta);
}

static void run(unsigned int tc_index)
{
	struct time64_variants *tv = &variants[tst_variant];
	struct timespec begin;
	struct timespec sleep_parent = {
		.tv_sec = PARENT_SLEEP_S,
	};

	if (!SAFE_FORK()) {
		child_nanosleep(tv, tc_index ? TIMER_ABSTIME : 0);
		exit(0);
	}

	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &begin);
	SAFE_CLOCK_NANOSLEEP(CLOCK_REALTIME, 0, &sleep_parent, NULL);
	SAFE_CLOCK_SETTIME(CLOCK_REALTIME, &begin);
}

static void setup(void)
{
	sleep_child->type = variants[tst_variant].ts_type;

	tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
}

static struct tst_test test = {
	.test = run,
	.setup = setup,
	.tcnt = 2,
	.needs_root = 1,
	.forks_child = 1,
	.restore_wallclock = 1,
	.test_variants = ARRAY_SIZE(variants),
	.bufs = (struct tst_buffers []) {
		{&sleep_child, .size = sizeof(struct tst_ts)},
		{},
	}
};

-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list