tools/testing/selftests/timens/timens.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/timens/timens.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/timens/timens.c
Extension
.c
Size
4266 bytes
Lines
190
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct test_clock {
	clockid_t id;
	char *name;
	/*
	 * off_id is -1 if a clock has own offset, or it contains an index
	 * which contains a right offset of this clock.
	 */
	int off_id;
	time_t offset;
};

#define ct(clock, off_id)	{ clock, #clock, off_id }
static struct test_clock clocks[] = {
	ct(CLOCK_BOOTTIME, -1),
	ct(CLOCK_BOOTTIME_ALARM, 1),
	ct(CLOCK_MONOTONIC, -1),
	ct(CLOCK_MONOTONIC_COARSE, 1),
	ct(CLOCK_MONOTONIC_RAW, 1),
};
#undef ct

static int child_ns, parent_ns = -1;

static int switch_ns(int fd)
{
	if (setns(fd, CLONE_NEWTIME)) {
		pr_perror("setns()");
		return -1;
	}

	return 0;
}

static int init_namespaces(void)
{
	char path[] = "/proc/self/ns/time_for_children";
	struct stat st1, st2;

	if (parent_ns == -1) {
		parent_ns = open(path, O_RDONLY);
		if (parent_ns <= 0)
			return pr_perror("Unable to open %s", path);
	}

	if (fstat(parent_ns, &st1))
		return pr_perror("Unable to stat the parent timens");

	if (unshare_timens())
		return  -1;

	child_ns = open(path, O_RDONLY);
	if (child_ns <= 0)
		return pr_perror("Unable to open %s", path);

	if (fstat(child_ns, &st2))
		return pr_perror("Unable to stat the timens");

	if (st1.st_ino == st2.st_ino)
		return pr_perror("The same child_ns after CLONE_NEWTIME");

	return 0;
}

static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
{
	struct timespec child_ts_new, parent_ts_old, cur_ts;
	char *entry = raw_syscall ? "syscall" : "vdso";
	double precision = 0.0;

	if (check_skip(clocks[clock_index].id))
		return 0;

	switch (clocks[clock_index].id) {
	case CLOCK_MONOTONIC_COARSE:
	case CLOCK_MONOTONIC_RAW:
		precision = -2.0;
		break;
	}

	if (switch_ns(parent_ns))
		return pr_err("switch_ns(%d)", child_ns);

	if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
		return -1;

	child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
	child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;

	if (switch_ns(child_ns))
		return pr_err("switch_ns(%d)", child_ns);

Annotation

Implementation Notes