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 
43 static volatile int timeout;
44 
sighandler(int signal)45 static void sighandler(int signal)
46 {
47 	if (signal == SIGALRM)
48 		timeout = 1;
49 }
50 
51 static volatile int k;
52 
work(void)53 static 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 
generate_utime(void)64 static void generate_utime(void)
65 {
66 	alarm(1);
67 	work();
68 }
69 
generate_stime(void)70 static 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 
verify_times(void)91 static 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  */
do_test(void)196 static void do_test(void)
197 {
198 	int pid = SAFE_FORK();
199 
200 	if (!pid)
201 		verify_times();
202 }
203 
setup(void)204 static void setup(void)
205 {
206 	SAFE_SIGNAL(SIGALRM, sighandler);
207 }
208 
209 static struct tst_test test = {
210 	.setup = setup,
211 	.forks_child = 1,
212 	.test_all = do_test,
213 };
214