1/*
2 * Copyright (c) International Business Machines  Corp., 2001
3 * Copyright (C) 2017 Cyril Hrubis <chrubis@suse.cz>
4 *
5 * This program is free software;  you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program;  if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19/*
20 * DESCRIPTION
21 *	Testcase to check the basic functionality of the times() system call.
22 *
23 * ALGORITHM
24 *	This testcase checks the values that times(2) system call returns.
25 *	Start a process, and spend some CPU time by performing a spin in
26 *	a for-loop. Then use the times() system call, to determine the
27 *	cpu time/sleep time, and other statistics.
28 *
29 * History
30 *	07/2001 John George
31 */
32
33#include <sys/types.h>
34#include <sys/times.h>
35#include <errno.h>
36#include <sys/wait.h>
37#include <time.h>
38#include <signal.h>
39#include <stdlib.h>
40
41#include "tst_test.h"
42
43static volatile int timeout;
44
45static void sighandler(int signal)
46{
47	if (signal == SIGALRM)
48		timeout = 1;
49}
50
51static volatile int k;
52
53static void work(void)
54{
55	int i, j;
56
57	while (!timeout)
58		for (i = 0; i < 10000; i++)
59			for (j = 0; j < 100; j++)
60				k = i * j;
61	timeout = 0;
62}
63
64static void generate_utime(void)
65{
66	alarm(1);
67	work();
68}
69
70static void generate_stime(void)
71{
72	time_t start_time, end_time;
73	struct tms buf;
74
75	/*
76	 * At least some CPU time must be used in system space. This is
77	 * achieved by executing the times(2) call for
78	 * atleast 2 secs. This logic makes it independant
79	 * of the processor speed.
80	 */
81	start_time = time(NULL);
82	for (;;) {
83		if (times(&buf) == -1)
84			tst_res(TFAIL | TERRNO, "times failed");
85		end_time = time(NULL);
86		if ((end_time - start_time) > 2)
87			return;
88	}
89}
90
91static void verify_times(void)
92{
93	int pid;
94	struct tms buf1, buf2, buf3;
95
96	if (times(&buf1) == -1)
97		tst_brk(TBROK | TERRNO, "times()");
98
99	if (buf1.tms_utime != 0)
100		tst_res(TFAIL, "buf1.tms_utime = %li", buf1.tms_utime);
101	else
102		tst_res(TPASS, "buf1.tms_utime = 0");
103
104	if (buf1.tms_stime != 0)
105		tst_res(TFAIL, "buf1.tms_stime = %li", buf1.tms_stime);
106	else
107		tst_res(TPASS, "buf1.tms_stime = 0");
108
109	generate_utime();
110	generate_stime();
111
112	if (times(&buf2) == -1)
113		tst_brk(TBROK | TERRNO, "times()");
114
115	if (buf2.tms_utime == 0)
116		tst_res(TFAIL, "buf2.tms_utime = 0");
117	else
118		tst_res(TPASS, "buf2.tms_utime = %li", buf2.tms_utime);
119
120	if (buf1.tms_utime >= buf2.tms_utime) {
121		tst_res(TFAIL, "buf1.tms_utime (%li) >= buf2.tms_utime (%li)",
122			buf1.tms_utime, buf2.tms_utime);
123	} else {
124		tst_res(TPASS, "buf1.tms_utime (%li) < buf2.tms_utime (%li)",
125			buf1.tms_utime, buf2.tms_utime);
126	}
127
128	if (buf2.tms_stime == 0)
129		tst_res(TFAIL, "buf2.tms_stime = 0");
130	else
131		tst_res(TPASS, "buf2.tms_stime = %li", buf2.tms_stime);
132
133	if (buf1.tms_stime >= buf2.tms_stime) {
134		tst_res(TFAIL, "buf1.tms_stime (%li) >= buf2.tms_stime (%li)",
135			buf1.tms_stime, buf2.tms_stime);
136	} else {
137		tst_res(TPASS, "buf1.tms_stime (%li) < buf2.tms_stime (%li)",
138			buf1.tms_stime, buf2.tms_stime);
139	}
140
141	if (buf2.tms_cutime != 0)
142		tst_res(TFAIL, "buf2.tms_cutime = %li", buf2.tms_cutime);
143	else
144		tst_res(TPASS, "buf2.tms_cutime = 0");
145
146	if (buf2.tms_cstime != 0)
147		tst_res(TFAIL, "buf2.tms_cstime = %li", buf2.tms_cstime);
148	else
149		tst_res(TPASS, "buf2.tms_cstime = 0");
150
151	pid = SAFE_FORK();
152
153	if (!pid) {
154		generate_utime();
155		generate_stime();
156		exit(0);
157	}
158
159	SAFE_WAITPID(pid, NULL, 0);
160
161	if (times(&buf3) == -1)
162		tst_brk(TBROK | TERRNO, "times()");
163
164	if (buf2.tms_utime > buf3.tms_utime) {
165		tst_res(TFAIL, "buf2.tms_utime (%li) > buf3.tms_utime (%li)",
166			buf2.tms_utime, buf3.tms_utime);
167	} else {
168		tst_res(TPASS, "buf2.tms_utime (%li) <= buf3.tms_utime (%li)",
169			buf2.tms_utime, buf3.tms_utime);
170	}
171
172	if (buf2.tms_stime > buf3.tms_stime) {
173		tst_res(TFAIL, "buf2.tms_stime (%li) > buf3.tms_stime (%li)",
174			buf2.tms_stime, buf3.tms_stime);
175	} else {
176		tst_res(TPASS, "buf2.tms_stime (%li) <= buf3.tms_stime (%li)",
177			buf2.tms_stime, buf3.tms_stime);
178	}
179
180	if (buf3.tms_cutime == 0)
181		tst_res(TFAIL, "buf3.tms_cutime = 0");
182	else
183		tst_res(TPASS, "buf3.tms_cutime = %ld", buf3.tms_cutime);
184
185	if (buf3.tms_cstime == 0)
186		tst_res(TFAIL, "buf3.tms_cstime = 0");
187	else
188		tst_res(TPASS, "buf3.tms_cstime = %ld", buf3.tms_cstime);
189
190	exit(0);
191}
192
193/*
194 * Run the test in a child to reset times in case of -i option.
195 */
196static void do_test(void)
197{
198	int pid = SAFE_FORK();
199
200	if (!pid)
201		verify_times();
202}
203
204static void setup(void)
205{
206	SAFE_SIGNAL(SIGALRM, sighandler);
207}
208
209static struct tst_test test = {
210	.tid = "times03",
211	.setup = setup,
212	.forks_child = 1,
213	.test_all = do_test,
214};
215