1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * Copyright (C) 2017 Cyril Hrubis <[email protected]>
5 */
6 /*
7 * DESCRIPTION
8 * Testcase to check the basic functionality of the times() system call.
9 *
10 * ALGORITHM
11 * This testcase checks the values that times(2) system call returns.
12 * Start a process, and spend some CPU time by performing a spin in
13 * a for-loop. Then use the times() system call, to determine the
14 * cpu time/sleep time, and other statistics.
15 *
16 * History
17 * 07/2001 John George
18 */
19
20 #include <sys/types.h>
21 #include <sys/times.h>
22 #include <errno.h>
23 #include <sys/wait.h>
24 #include <time.h>
25 #include <signal.h>
26 #include <stdlib.h>
27
28 #include "tst_test.h"
29
30 static volatile int timeout;
31
sighandler(int signal)32 static void sighandler(int signal)
33 {
34 if (signal == SIGALRM)
35 timeout = 1;
36 }
37
38 static volatile int k;
39
work(void)40 static void work(void)
41 {
42 int i, j;
43
44 while (!timeout)
45 for (i = 0; i < 10000; i++)
46 for (j = 0; j < 100; j++)
47 k = i * j;
48 timeout = 0;
49 }
50
generate_utime(void)51 static void generate_utime(void)
52 {
53 alarm(1);
54 work();
55 }
56
generate_stime(void)57 static void generate_stime(void)
58 {
59 time_t start_time, end_time;
60 struct tms buf;
61
62 /*
63 * At least some CPU time must be used in system space. This is
64 * achieved by executing the times(2) call for
65 * at least 2 secs. This logic makes it independent
66 * of the processor speed.
67 */
68 start_time = time(NULL);
69 for (;;) {
70 if (times(&buf) == -1)
71 tst_res(TFAIL | TERRNO, "times failed");
72 end_time = time(NULL);
73 if ((end_time - start_time) > 2)
74 return;
75 }
76 }
77
verify_times(void)78 static void verify_times(void)
79 {
80 int pid;
81 struct tms buf1, buf2, buf3;
82
83 if (times(&buf1) == -1)
84 tst_brk(TBROK | TERRNO, "times()");
85
86 if (buf1.tms_utime > 5)
87 tst_res(TFAIL, "buf1.tms_utime = %li", buf1.tms_utime);
88 else
89 tst_res(TPASS, "buf1.tms_utime <= 5");
90
91 if (buf1.tms_stime > 5)
92 tst_res(TFAIL, "buf1.tms_stime = %li", buf1.tms_stime);
93 else
94 tst_res(TPASS, "buf1.tms_stime <= 5");
95
96 generate_utime();
97 generate_stime();
98
99 if (times(&buf2) == -1)
100 tst_brk(TBROK | TERRNO, "times()");
101
102 if (buf2.tms_utime == 0)
103 tst_res(TFAIL, "buf2.tms_utime = 0");
104 else
105 tst_res(TPASS, "buf2.tms_utime = %li", buf2.tms_utime);
106
107 if (buf1.tms_utime >= buf2.tms_utime) {
108 tst_res(TFAIL, "buf1.tms_utime (%li) >= buf2.tms_utime (%li)",
109 buf1.tms_utime, buf2.tms_utime);
110 } else {
111 tst_res(TPASS, "buf1.tms_utime (%li) < buf2.tms_utime (%li)",
112 buf1.tms_utime, buf2.tms_utime);
113 }
114
115 if (buf2.tms_stime == 0)
116 tst_res(TFAIL, "buf2.tms_stime = 0");
117 else
118 tst_res(TPASS, "buf2.tms_stime = %li", buf2.tms_stime);
119
120 if (buf1.tms_stime >= buf2.tms_stime) {
121 tst_res(TFAIL, "buf1.tms_stime (%li) >= buf2.tms_stime (%li)",
122 buf1.tms_stime, buf2.tms_stime);
123 } else {
124 tst_res(TPASS, "buf1.tms_stime (%li) < buf2.tms_stime (%li)",
125 buf1.tms_stime, buf2.tms_stime);
126 }
127
128 if (buf2.tms_cutime != 0)
129 tst_res(TFAIL, "buf2.tms_cutime = %li", buf2.tms_cutime);
130 else
131 tst_res(TPASS, "buf2.tms_cutime = 0");
132
133 if (buf2.tms_cstime != 0)
134 tst_res(TFAIL, "buf2.tms_cstime = %li", buf2.tms_cstime);
135 else
136 tst_res(TPASS, "buf2.tms_cstime = 0");
137
138 pid = SAFE_FORK();
139
140 if (!pid) {
141 generate_utime();
142 generate_stime();
143 exit(0);
144 }
145
146 SAFE_WAITPID(pid, NULL, 0);
147
148 if (times(&buf3) == -1)
149 tst_brk(TBROK | TERRNO, "times()");
150
151 if (buf2.tms_utime > buf3.tms_utime) {
152 tst_res(TFAIL, "buf2.tms_utime (%li) > buf3.tms_utime (%li)",
153 buf2.tms_utime, buf3.tms_utime);
154 } else {
155 tst_res(TPASS, "buf2.tms_utime (%li) <= buf3.tms_utime (%li)",
156 buf2.tms_utime, buf3.tms_utime);
157 }
158
159 if (buf2.tms_stime > buf3.tms_stime) {
160 tst_res(TFAIL, "buf2.tms_stime (%li) > buf3.tms_stime (%li)",
161 buf2.tms_stime, buf3.tms_stime);
162 } else {
163 tst_res(TPASS, "buf2.tms_stime (%li) <= buf3.tms_stime (%li)",
164 buf2.tms_stime, buf3.tms_stime);
165 }
166
167 if (buf3.tms_cutime == 0)
168 tst_res(TFAIL, "buf3.tms_cutime = 0");
169 else
170 tst_res(TPASS, "buf3.tms_cutime = %ld", buf3.tms_cutime);
171
172 if (buf3.tms_cstime == 0)
173 tst_res(TFAIL, "buf3.tms_cstime = 0");
174 else
175 tst_res(TPASS, "buf3.tms_cstime = %ld", buf3.tms_cstime);
176
177 exit(0);
178 }
179
180 /*
181 * Run the test in a child to reset times in case of -i option.
182 */
do_test(void)183 static void do_test(void)
184 {
185 int pid = SAFE_FORK();
186
187 if (!pid)
188 verify_times();
189 }
190
setup(void)191 static void setup(void)
192 {
193 SAFE_SIGNAL(SIGALRM, sighandler);
194 }
195
196 static struct tst_test test = {
197 .setup = setup,
198 .forks_child = 1,
199 .test_all = do_test,
200 };
201