1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2019 Linaro Limited. All rights reserved.
4f08c3bdfSopenharmony_ci * Author: Rafael David Tinoco <rafael.tinoco@linaro.org>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci/*
7f08c3bdfSopenharmony_ci * Basic test for clock_gettime(2) on multiple clocks:
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci *  1) CLOCK_REALTIME
10f08c3bdfSopenharmony_ci *  2) CLOCK_MONOTONIC
11f08c3bdfSopenharmony_ci *  3) CLOCK_PROCESS_CPUTIME_ID
12f08c3bdfSopenharmony_ci *  4) CLOCK_THREAD_CPUTIME_ID
13f08c3bdfSopenharmony_ci *  5) CLOCK_REALTIME_COARSE
14f08c3bdfSopenharmony_ci *  6) CLOCK_MONOTONIC_COARSE
15f08c3bdfSopenharmony_ci *  7) CLOCK_MONOTONIC_RAW
16f08c3bdfSopenharmony_ci *  8) CLOCK_BOOTTIME
17f08c3bdfSopenharmony_ci */
18f08c3bdfSopenharmony_ci
19f08c3bdfSopenharmony_ci#include "config.h"
20f08c3bdfSopenharmony_ci#include "time64_variants.h"
21f08c3bdfSopenharmony_ci#include "tst_timer.h"
22f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h"
23f08c3bdfSopenharmony_ci
24f08c3bdfSopenharmony_cistruct test_case {
25f08c3bdfSopenharmony_ci	clockid_t clktype;
26f08c3bdfSopenharmony_ci	int allow_inval;
27f08c3bdfSopenharmony_ci};
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_cistatic struct test_case tc[] = {
30f08c3bdfSopenharmony_ci	{
31f08c3bdfSopenharmony_ci	 .clktype = CLOCK_REALTIME,
32f08c3bdfSopenharmony_ci	 },
33f08c3bdfSopenharmony_ci	{
34f08c3bdfSopenharmony_ci	 .clktype = CLOCK_MONOTONIC,
35f08c3bdfSopenharmony_ci	 },
36f08c3bdfSopenharmony_ci	{
37f08c3bdfSopenharmony_ci	 .clktype = CLOCK_PROCESS_CPUTIME_ID,
38f08c3bdfSopenharmony_ci	 },
39f08c3bdfSopenharmony_ci	{
40f08c3bdfSopenharmony_ci	 .clktype = CLOCK_THREAD_CPUTIME_ID,
41f08c3bdfSopenharmony_ci	 },
42f08c3bdfSopenharmony_ci	{
43f08c3bdfSopenharmony_ci	 .clktype = CLOCK_REALTIME_COARSE,
44f08c3bdfSopenharmony_ci	 .allow_inval = 1,
45f08c3bdfSopenharmony_ci	 },
46f08c3bdfSopenharmony_ci	{
47f08c3bdfSopenharmony_ci	 .clktype = CLOCK_MONOTONIC_COARSE,
48f08c3bdfSopenharmony_ci	 .allow_inval = 1,
49f08c3bdfSopenharmony_ci	 },
50f08c3bdfSopenharmony_ci	{
51f08c3bdfSopenharmony_ci	 .clktype = CLOCK_MONOTONIC_RAW,
52f08c3bdfSopenharmony_ci	 .allow_inval = 1,
53f08c3bdfSopenharmony_ci	 },
54f08c3bdfSopenharmony_ci	{
55f08c3bdfSopenharmony_ci	 .clktype = CLOCK_BOOTTIME,
56f08c3bdfSopenharmony_ci	 .allow_inval = 1,
57f08c3bdfSopenharmony_ci	 },
58f08c3bdfSopenharmony_ci};
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_cistatic struct tst_ts spec;
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_cistatic struct time64_variants variants[] = {
63f08c3bdfSopenharmony_ci	{ .clock_gettime = libc_clock_gettime, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"},
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_ci#if (__NR_clock_gettime != __LTP__NR_INVALID_SYSCALL)
66f08c3bdfSopenharmony_ci	{ .clock_gettime = sys_clock_gettime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"},
67f08c3bdfSopenharmony_ci#endif
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci#if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL)
70f08c3bdfSopenharmony_ci	{ .clock_gettime = sys_clock_gettime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"},
71f08c3bdfSopenharmony_ci#endif
72f08c3bdfSopenharmony_ci};
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_cistatic void setup(void)
75f08c3bdfSopenharmony_ci{
76f08c3bdfSopenharmony_ci	long unsigned utime;
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc);
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci	do {
81f08c3bdfSopenharmony_ci		SAFE_FILE_SCANF("/proc/self/stat",
82f08c3bdfSopenharmony_ci			"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu",
83f08c3bdfSopenharmony_ci			&utime);
84f08c3bdfSopenharmony_ci	} while (utime == 0);
85f08c3bdfSopenharmony_ci}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_cistatic void verify_clock_gettime(unsigned int i)
88f08c3bdfSopenharmony_ci{
89f08c3bdfSopenharmony_ci	struct time64_variants *tv = &variants[tst_variant];
90f08c3bdfSopenharmony_ci	int ret;
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ci	memset(&spec, 0, sizeof(spec));
93f08c3bdfSopenharmony_ci	spec.type = tv->ts_type;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	TEST(tv->clock_gettime(tc[i].clktype, tst_ts_get(&spec)));
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci	if (TST_RET == -1) {
98f08c3bdfSopenharmony_ci		/* errors: allow unsupported clock types */
99f08c3bdfSopenharmony_ci		if (tc[i].allow_inval && TST_ERR == EINVAL) {
100f08c3bdfSopenharmony_ci			tst_res(TPASS, "clock_gettime(2): unsupported clock %s failed as expected",
101f08c3bdfSopenharmony_ci				tst_clock_name(tc[i].clktype));
102f08c3bdfSopenharmony_ci		} else {
103f08c3bdfSopenharmony_ci			tst_res(TFAIL | TTERRNO, "clock_gettime(2): clock %s failed unexpectedly",
104f08c3bdfSopenharmony_ci				tst_clock_name(tc[i].clktype));
105f08c3bdfSopenharmony_ci		}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_ci	} else {
108f08c3bdfSopenharmony_ci		/* success: also check if timespec was changed */
109f08c3bdfSopenharmony_ci		ret = tst_ts_valid(&spec);
110f08c3bdfSopenharmony_ci		if (!ret) {
111f08c3bdfSopenharmony_ci			tst_res(TPASS, "clock_gettime(2): clock %s passed",
112f08c3bdfSopenharmony_ci				tst_clock_name(tc[i].clktype));
113f08c3bdfSopenharmony_ci		} else if (ret == -1) {
114f08c3bdfSopenharmony_ci			tst_res(TFAIL, "clock_gettime(2): clock %s passed, unchanged timespec",
115f08c3bdfSopenharmony_ci				tst_clock_name(tc[i].clktype));
116f08c3bdfSopenharmony_ci		} else if (ret == -2) {
117f08c3bdfSopenharmony_ci			tst_res(TFAIL, "clock_gettime(2): clock %s passed, Corrupted timespec",
118f08c3bdfSopenharmony_ci				tst_clock_name(tc[i].clktype));
119f08c3bdfSopenharmony_ci		}
120f08c3bdfSopenharmony_ci	}
121f08c3bdfSopenharmony_ci}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_cistatic struct tst_test test = {
124f08c3bdfSopenharmony_ci	.test = verify_clock_gettime,
125f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tc),
126f08c3bdfSopenharmony_ci	.test_variants = ARRAY_SIZE(variants),
127f08c3bdfSopenharmony_ci	.setup = setup,
128f08c3bdfSopenharmony_ci	.needs_root = 1,
129f08c3bdfSopenharmony_ci};
130