1 /*
2 * Check decoding of times syscall.
3 *
4 * Copyright (c) 2015-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
6 * Copyright (c) 2015-2023 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 /**
13 * @file
14 * This test burns some CPU cycles in user space and kernel space in order to
15 * get some non-zero values returned by times(2).
16 */
17
18 #include "tests.h"
19 #include <fcntl.h>
20 #include <sched.h>
21 #include <stdio.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include "scno.h"
26 #include <sys/stat.h>
27 #include <sys/times.h>
28 #include <sys/types.h>
29 #include <sys/wait.h>
30
31 #include "time_enjoyment.h"
32
33 enum {
34 PARENT_CPUTIME_LIMIT_NSEC = 300000000,
35 CHILD_CPUTIME_LIMIT_NSEC = 500000000,
36 };
37
38 int
39 main(void)
40 {
41 enjoy_time(PARENT_CPUTIME_LIMIT_NSEC);
42
43 pid_t pid = fork();
44 if (pid < 0)
45 perror_msg_and_fail("fork");
46
47 if (pid == 0) {
48 enjoy_time(CHILD_CPUTIME_LIMIT_NSEC);
49
50 return 0;
51 } else {
52 wait(NULL);
53 }
54
55 struct tms tbuf;
56 unsigned long long llres;
57
58 /*
59 * On systems where user's and kernel's long types are the same,
60 * prefer direct times syscall over libc's times function because
61 * the latter is more prone to return value truncation.
62 */
63
64 #if defined __x86_64__ && defined __ILP32__
65 register long arg asm("rdi") = (long) &tbuf;
66 asm volatile("syscall\n\t"
67 : "=a"(llres)
68 : "0"(__NR_times), "r"(arg)
69 : "memory", "cc", "r11", "cx");
70 if (llres > 0xfffffffffffff000)
71 return 77;
72 #elif defined __s390__ || defined LINUX_MIPSN32
73 clock_t res = times(&tbuf);
74
75 if ((clock_t) -1 == res)
76 perror_msg_and_skip("times");
77 if (sizeof(res) < sizeof(unsigned long long))
78 llres = (unsigned long) res;
79 else
80 llres = res;
81 #else
82 long res = syscall(__NR_times, &tbuf);
83
84 if (-1L == res)
85 perror_msg_and_skip("times");
86 else
87 llres = (unsigned long) res;
88 #endif
89
90 long clk_tck = sysconf(_SC_CLK_TCK);
91 int precision = clk_tck > 100000000 ? 9
92 : clk_tck > 10000000 ? 8
93 : clk_tck > 1000000 ? 7
94 : clk_tck > 100000 ? 6
95 : clk_tck > 10000 ? 5
96 : clk_tck > 1000 ? 4
97 : clk_tck > 100 ? 3
98 : clk_tck > 10 ? 2
99 : clk_tck > 1 ? 1 : 0;
100
101 if (!XLAT_RAW && clk_tck > 0) {
102 printf("times({tms_utime=%llu /* %.*f s */"
103 ", tms_stime=%llu /* %.*f s */"
104 ", tms_cutime=%llu /* %.*f s */"
105 ", tms_cstime=%llu /* %.*f s */}) = %llu\n",
106 (unsigned long long) tbuf.tms_utime,
107 precision, (double) tbuf.tms_utime / clk_tck,
108 (unsigned long long) tbuf.tms_stime,
109 precision, (double) tbuf.tms_stime / clk_tck,
110 (unsigned long long) tbuf.tms_cutime,
111 precision, (double) tbuf.tms_cutime / clk_tck,
112 (unsigned long long) tbuf.tms_cstime,
113 precision, (double) tbuf.tms_cstime / clk_tck,
114 llres);
115 } else {
116 printf("times({tms_utime=%llu, tms_stime=%llu"
117 ", tms_cutime=%llu, tms_cstime=%llu}) = %llu\n",
118 (unsigned long long) tbuf.tms_utime,
119 (unsigned long long) tbuf.tms_stime,
120 (unsigned long long) tbuf.tms_cutime,
121 (unsigned long long) tbuf.tms_cstime,
122 llres);
123 }
124
125 puts("+++ exited with 0 +++");
126
127 return 0;
128 }