1// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2/*
3 * vdso_clock_getres.c: Sample code to test clock_getres.
4 * Copyright (c) 2019 Arm Ltd.
5 *
6 * Compile with:
7 * gcc -std=gnu99 vdso_clock_getres.c
8 *
9 * Tested on ARM, ARM64, MIPS32, x86 (32-bit and 64-bit),
10 * Power (32-bit and 64-bit), S390x (32-bit and 64-bit).
11 * Might work on other architectures.
12 */
13
14#define _GNU_SOURCE
15#include <elf.h>
16#include <err.h>
17#include <fcntl.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <time.h>
22#include <sys/auxv.h>
23#include <sys/mman.h>
24#include <sys/time.h>
25#include <unistd.h>
26#include <sys/syscall.h>
27
28#include "../kselftest.h"
29
30static long syscall_clock_getres(clockid_t _clkid, struct timespec *_ts)
31{
32	long ret;
33
34	ret = syscall(SYS_clock_getres, _clkid, _ts);
35
36	return ret;
37}
38
39const char *vdso_clock_name[12] = {
40	"CLOCK_REALTIME",
41	"CLOCK_MONOTONIC",
42	"CLOCK_PROCESS_CPUTIME_ID",
43	"CLOCK_THREAD_CPUTIME_ID",
44	"CLOCK_MONOTONIC_RAW",
45	"CLOCK_REALTIME_COARSE",
46	"CLOCK_MONOTONIC_COARSE",
47	"CLOCK_BOOTTIME",
48	"CLOCK_REALTIME_ALARM",
49	"CLOCK_BOOTTIME_ALARM",
50	"CLOCK_SGI_CYCLE",
51	"CLOCK_TAI",
52};
53
54/*
55 * This function calls clock_getres in vdso and by system call
56 * with different values for clock_id.
57 *
58 * Example of output:
59 *
60 * clock_id: CLOCK_REALTIME [PASS]
61 * clock_id: CLOCK_BOOTTIME [PASS]
62 * clock_id: CLOCK_TAI [PASS]
63 * clock_id: CLOCK_REALTIME_COARSE [PASS]
64 * clock_id: CLOCK_MONOTONIC [PASS]
65 * clock_id: CLOCK_MONOTONIC_RAW [PASS]
66 * clock_id: CLOCK_MONOTONIC_COARSE [PASS]
67 */
68static inline int vdso_test_clock(unsigned int clock_id)
69{
70	struct timespec x, y;
71
72	printf("clock_id: %s", vdso_clock_name[clock_id]);
73	clock_getres(clock_id, &x);
74	syscall_clock_getres(clock_id, &y);
75
76	if ((x.tv_sec != y.tv_sec) || (x.tv_nsec != y.tv_nsec)) {
77		printf(" [FAIL]\n");
78		return KSFT_FAIL;
79	}
80
81	printf(" [PASS]\n");
82	return KSFT_PASS;
83}
84
85int main(int argc, char **argv)
86{
87	int ret = 0;
88
89#if _POSIX_TIMERS > 0
90
91#ifdef CLOCK_REALTIME
92	ret += vdso_test_clock(CLOCK_REALTIME);
93#endif
94
95#ifdef CLOCK_BOOTTIME
96	ret += vdso_test_clock(CLOCK_BOOTTIME);
97#endif
98
99#ifdef CLOCK_TAI
100	ret += vdso_test_clock(CLOCK_TAI);
101#endif
102
103#ifdef CLOCK_REALTIME_COARSE
104	ret += vdso_test_clock(CLOCK_REALTIME_COARSE);
105#endif
106
107#ifdef CLOCK_MONOTONIC
108	ret += vdso_test_clock(CLOCK_MONOTONIC);
109#endif
110
111#ifdef CLOCK_MONOTONIC_RAW
112	ret += vdso_test_clock(CLOCK_MONOTONIC_RAW);
113#endif
114
115#ifdef CLOCK_MONOTONIC_COARSE
116	ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE);
117#endif
118
119#endif
120	if (ret > 0)
121		return KSFT_FAIL;
122
123	return KSFT_PASS;
124}
125