1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) International Business Machines Corp., 2001
4 * Copyright (C) 2017 Cyril Hrubis <chrubis@suse.cz>
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
30static volatile int timeout;
31
32static void sighandler(int signal)
33{
34	if (signal == SIGALRM)
35		timeout = 1;
36}
37
38static volatile int k;
39
40static 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
51static void generate_utime(void)
52{
53	alarm(1);
54	work();
55}
56
57static 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
78static 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 */
183static void do_test(void)
184{
185	int pid = SAFE_FORK();
186
187	if (!pid)
188		verify_times();
189}
190
191static void setup(void)
192{
193	SAFE_SIGNAL(SIGALRM, sighandler);
194}
195
196static struct tst_test test = {
197	.setup = setup,
198	.forks_child = 1,
199	.test_all = do_test,
200};
201