xref: /openbsd/regress/lib/libc/sys/t_getrusage.c (revision 09467b48)
1 /*	$OpenBSD: t_getrusage.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $	*/
2 /* $NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $ */
3 
4 /*-
5  * Copyright (c) 2011 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jukka Ruohonen.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "macros.h"
34 
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $");
37 
38 #include <sys/resource.h>
39 #include <sys/time.h>
40 
41 #include "atf-c.h"
42 #include <stdio.h>
43 #include <errno.h>
44 #include <limits.h>
45 #include <signal.h>
46 #include <stdint.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <fcntl.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 
53 static void		work(void);
54 static void		sighandler(int);
55 
56 static const size_t	maxiter = 2000;
57 
58 static void
59 sighandler(int signo __unused)
60 {
61 	/* Nothing. */
62 }
63 
64 static void
65 work(void)
66 {
67 	size_t n = UINT16_MAX * 10;
68 
69 	while (n > 0) {
70 #ifdef __or1k__
71 		 asm volatile("l.nop");	/* Do something. */
72 #elif defined(__ia64__)
73 		 asm volatile("nop 0"); /* Do something. */
74 #else
75 		 asm volatile("nop");	/* Do something. */
76 #endif
77 		 n--;
78 	}
79 }
80 
81 ATF_TC(getrusage_err);
82 ATF_TC_HEAD(getrusage_err, tc)
83 {
84 	atf_tc_set_md_var(tc, "descr", "Test error conditions");
85 }
86 
87 ATF_TC_BODY(getrusage_err, tc)
88 {
89 	struct rusage ru;
90 
91 	errno = 0;
92 
93 	ATF_REQUIRE(getrusage(INT_MAX, &ru) != 0);
94 	ATF_REQUIRE(errno == EINVAL);
95 
96 	errno = 0;
97 
98 	ATF_REQUIRE(getrusage(RUSAGE_SELF, (void *)0) != 0);
99 	ATF_REQUIRE(errno == EFAULT);
100 }
101 
102 ATF_TC(getrusage_sig);
103 ATF_TC_HEAD(getrusage_sig, tc)
104 {
105 	atf_tc_set_md_var(tc, "descr", "Test signal count with getrusage(2)");
106 }
107 
108 ATF_TC_BODY(getrusage_sig, tc)
109 {
110 	struct rusage ru;
111 	const long n = 5;
112 	int i;
113 
114 	/*
115 	 * Test that signals are recorded.
116 	 */
117 	ATF_REQUIRE(signal(SIGUSR1, sighandler) != SIG_ERR);
118 
119 	for (i = 0; i < n; i++)
120 		ATF_REQUIRE(raise(SIGUSR1) == 0);
121 
122 	(void)memset(&ru, 0, sizeof(struct rusage));
123 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
124 
125 	if (n != ru.ru_nsignals)
126 		atf_tc_fail("getrusage(2) did not record signals");
127 }
128 
129 ATF_TC(getrusage_maxrss);
130 ATF_TC_HEAD(getrusage_maxrss, tc)
131 {
132 	atf_tc_set_md_var(tc, "descr", "Test maxrss growing with getrusage(2)");
133 }
134 
135 ATF_TC_BODY(getrusage_maxrss, tc)
136 {
137 	struct rusage ru;
138 	long maxrss;
139 	int i, fd;
140 
141 #define	DUMP_FILE	"dump"
142 
143 	fd = open(DUMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0222);
144 	ATF_REQUIRE(fd != -1);
145 
146 	(void)memset(&ru, 0, sizeof(struct rusage));
147 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
148 	maxrss = ru.ru_maxrss;
149 
150 #define CHUNK (1024 * 1024)
151 	for (i = 0; i < 40; i++) {
152 		void *p = malloc(CHUNK);
153 		memset(p, 0, CHUNK);
154 		write(fd, p, CHUNK);
155 	}
156 	close(fd);
157 	unlink(DUMP_FILE);
158 
159 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
160 	ATF_REQUIRE_MSG(maxrss < ru.ru_maxrss,
161 	    "maxrss: %ld, ru.ru_maxrss: %ld", maxrss, ru.ru_maxrss);
162 }
163 
164 ATF_TC(getrusage_msgsnd);
165 ATF_TC_HEAD(getrusage_msgsnd, tc)
166 {
167 	atf_tc_set_md_var(tc, "descr", "Test send growing with getrusage(2)");
168 }
169 
170 ATF_TC_BODY(getrusage_msgsnd, tc)
171 {
172 	struct rusage ru;
173 	long msgsnd;
174 	int s, i;
175 	struct sockaddr_in sin;
176 
177 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
178 	msgsnd = ru.ru_msgsnd;
179 
180 	s = socket(AF_INET, SOCK_DGRAM, 0);
181 	ATF_REQUIRE(s >= 0);
182 	memset(&sin, 0, sizeof(sin));
183 	sin.sin_family = AF_INET;
184 	sin.sin_len = sizeof(sin);
185 	sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
186 	sin.sin_port = htons(3333);
187 
188 	for (i = 0; i < 10; i++)
189 		ATF_REQUIRE(sendto(s, &sin, sizeof(sin), 0, (void *)&sin,
190 			(socklen_t)sizeof(sin)) != -1);
191 
192 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
193 	ATF_REQUIRE(msgsnd + 10 == ru.ru_msgsnd);
194 	close(s);
195 }
196 
197 ATF_TC(getrusage_utime_back);
198 ATF_TC_HEAD(getrusage_utime_back, tc)
199 {
200 	atf_tc_set_md_var(tc, "descr", "Test bogus values from getrusage(2)");
201 }
202 
203 ATF_TC_BODY(getrusage_utime_back, tc)
204 {
205 	struct rusage ru1, ru2;
206 	size_t i;
207 
208 	/*
209 	 * Test that two consecutive calls are sane.
210 	 */
211 
212 	for (i = 0; i < maxiter; i++) {
213 
214 		(void)memset(&ru1, 0, sizeof(struct rusage));
215 		(void)memset(&ru2, 0, sizeof(struct rusage));
216 
217 		work();
218 
219 		ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru1) == 0);
220 
221 		work();
222 
223 		ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru2) == 0);
224 
225 		if (timercmp(&ru2.ru_utime, &ru1.ru_utime, <) != 0)
226 			atf_tc_fail("user time went backwards");
227 	}
228 }
229 
230 ATF_TC(getrusage_utime_zero);
231 ATF_TC_HEAD(getrusage_utime_zero, tc)
232 {
233 	atf_tc_set_md_var(tc, "descr", "Test zero utime from getrusage(2)");
234 }
235 
236 ATF_TC_BODY(getrusage_utime_zero, tc)
237 {
238 	struct rusage ru;
239 	size_t i;
240 
241 	/*
242 	 * Test that getrusage(2) does not return
243 	 * zero user time for the calling process.
244 	 */
245 
246 	for (i = 0; i < maxiter; i++) {
247 		work();
248 	}
249 
250 	(void)memset(&ru, 0, sizeof(struct rusage));
251 
252 	ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0);
253 
254 	if (ru.ru_utime.tv_sec == 0 && ru.ru_utime.tv_usec == 0)
255 		atf_tc_fail("zero user time from getrusage(2)");
256 }
257 
258 ATF_TP_ADD_TCS(tp)
259 {
260 
261 	ATF_TP_ADD_TC(tp, getrusage_err);
262 	ATF_TP_ADD_TC(tp, getrusage_sig);
263 	ATF_TP_ADD_TC(tp, getrusage_maxrss);
264 	ATF_TP_ADD_TC(tp, getrusage_msgsnd);
265 	ATF_TP_ADD_TC(tp, getrusage_utime_back);
266 	ATF_TP_ADD_TC(tp, getrusage_utime_zero);
267 
268 	return atf_no_error();
269 }
270