xref: /minix3/minix/tests/test75.c (revision 29346ab0430c05d7b81aa329f371aa4eaf0ded06)
1*29346ab0SDavid van Moolenbroek /* Test 75 - getrusage and wait4 test.
2433d6423SLionel Sambuc  */
3433d6423SLionel Sambuc 
4433d6423SLionel Sambuc #include <sys/resource.h>
5433d6423SLionel Sambuc #include <sys/time.h>
6433d6423SLionel Sambuc #include <stdio.h>
7433d6423SLionel Sambuc #include <assert.h>
8433d6423SLionel Sambuc #include <sys/types.h>
9433d6423SLionel Sambuc #include <sys/wait.h>
10*29346ab0SDavid van Moolenbroek #include <sys/mman.h>
11433d6423SLionel Sambuc #include <unistd.h>
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include "common.h"
14433d6423SLionel Sambuc 
15433d6423SLionel Sambuc #define CHECK_ZERO_FIELD(rusage, field)		\
16433d6423SLionel Sambuc 	if (rusage.field != 0)			\
17433d6423SLionel Sambuc 		em(1, #field " must be zero");
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #define CHECK_NOT_ZERO_FIELD(rusage, field)	\
20433d6423SLionel Sambuc 	if (rusage.field == 0)			\
21433d6423SLionel Sambuc 		em(1, #field " can't be zero");
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc #define CHECK_EQUAL_FIELD(rusage1, rusage2, field)		  \
24433d6423SLionel Sambuc 	if (rusage1.field != rusage2.field)			  \
25433d6423SLionel Sambuc 		em(1, #field " of " #rusage1 " doesn't equal to " \
26433d6423SLionel Sambuc 			#field " of " #rusage2);
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc static void
spin(void)29433d6423SLionel Sambuc spin(void)
30433d6423SLionel Sambuc {
31433d6423SLionel Sambuc 	struct timeval start_time;
32433d6423SLionel Sambuc 	struct timeval end_time;
33433d6423SLionel Sambuc 	unsigned int loop = 0;
34*29346ab0SDavid van Moolenbroek 	if (gettimeofday(&start_time, NULL) == -1) e(1);
35433d6423SLionel Sambuc 	end_time = start_time;
36433d6423SLionel Sambuc 	do {
37433d6423SLionel Sambuc 		if ((++loop % 3000000000) == 0) {
38*29346ab0SDavid van Moolenbroek 			if (gettimeofday(&end_time, NULL) == -1) e(1);
39433d6423SLionel Sambuc 		}
40433d6423SLionel Sambuc 	} while (start_time.tv_sec + 10 > end_time.tv_sec);
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc 
43*29346ab0SDavid van Moolenbroek /*
44*29346ab0SDavid van Moolenbroek  * Test getrusage(2).
45*29346ab0SDavid van Moolenbroek  */
46*29346ab0SDavid van Moolenbroek static void
test75a(void)47*29346ab0SDavid van Moolenbroek test75a(void)
48433d6423SLionel Sambuc {
49433d6423SLionel Sambuc 	struct rusage r_usage1;
50433d6423SLionel Sambuc 	struct rusage r_usage2;
51433d6423SLionel Sambuc 	struct rusage r_usage3;
52433d6423SLionel Sambuc 	pid_t child;
53433d6423SLionel Sambuc 	int status = 0;
54*29346ab0SDavid van Moolenbroek 
55433d6423SLionel Sambuc 	if ((getrusage(RUSAGE_SELF + 1, &r_usage1) != -1 || errno != EINVAL) ||
56433d6423SLionel Sambuc 	    (getrusage(RUSAGE_CHILDREN - 1, &r_usage1) != -1 ||
57433d6423SLionel Sambuc 	     errno != EINVAL) || (getrusage(RUSAGE_SELF, NULL) != -1 ||
58*29346ab0SDavid van Moolenbroek 	     errno != EFAULT))
59433d6423SLionel Sambuc 		e(1);
60*29346ab0SDavid van Moolenbroek 
61433d6423SLionel Sambuc 	spin();
62*29346ab0SDavid van Moolenbroek 	if (getrusage(RUSAGE_SELF, &r_usage1) != 0) e(1);
63433d6423SLionel Sambuc 	CHECK_NOT_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
64433d6423SLionel Sambuc 	CHECK_NOT_ZERO_FIELD(r_usage1, ru_maxrss);
65*29346ab0SDavid van Moolenbroek 	if (getrusage(RUSAGE_CHILDREN, &r_usage2) != 0) e(1);
66*29346ab0SDavid van Moolenbroek 
67433d6423SLionel Sambuc 	if ((child = fork()) == 0) {
68433d6423SLionel Sambuc 		/*
69433d6423SLionel Sambuc 		 * We cannot do this part of the test in the parent, since
70433d6423SLionel Sambuc 		 * start() calls system() which spawns a child process.
71433d6423SLionel Sambuc 		 */
72*29346ab0SDavid van Moolenbroek 		if (getrusage(RUSAGE_CHILDREN, &r_usage1) != 0) e(1);
73433d6423SLionel Sambuc 		CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
74433d6423SLionel Sambuc 		CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_usec);
75433d6423SLionel Sambuc 		spin();
76*29346ab0SDavid van Moolenbroek 		exit(errct);
77433d6423SLionel Sambuc 	} else {
78*29346ab0SDavid van Moolenbroek 		if (child != waitpid(child, &status, 0)) e(1);
79*29346ab0SDavid van Moolenbroek 		if (WEXITSTATUS(status) != 0) e(1);
80*29346ab0SDavid van Moolenbroek 		if (getrusage(RUSAGE_CHILDREN, &r_usage3) != 0) e(1);
81433d6423SLionel Sambuc 		CHECK_NOT_ZERO_FIELD(r_usage3, ru_utime.tv_sec);
82433d6423SLionel Sambuc 	}
83*29346ab0SDavid van Moolenbroek }
84*29346ab0SDavid van Moolenbroek 
85*29346ab0SDavid van Moolenbroek /*
86*29346ab0SDavid van Moolenbroek  * Test the wait4 system call with good and bad rusage pointers, and with the
87*29346ab0SDavid van Moolenbroek  * wait4 either being satisfied immediately or blocking until the child exits:
88*29346ab0SDavid van Moolenbroek  * - mode 0: child has exited when parent calls wait4;
89*29346ab0SDavid van Moolenbroek  * - mode 1: parent blocks waiting for child, using a bad rusage pointer;
90*29346ab0SDavid van Moolenbroek  * - mode 2: parent blocks waiting for child, using a good rusage pointer.
91*29346ab0SDavid van Moolenbroek  */
92*29346ab0SDavid van Moolenbroek static void
sub75b(int mode,void * bad_ptr)93*29346ab0SDavid van Moolenbroek sub75b(int mode, void * bad_ptr)
94*29346ab0SDavid van Moolenbroek {
95*29346ab0SDavid van Moolenbroek 	struct rusage r_usage;
96*29346ab0SDavid van Moolenbroek 	pid_t pid;
97*29346ab0SDavid van Moolenbroek 	int status;
98*29346ab0SDavid van Moolenbroek 
99*29346ab0SDavid van Moolenbroek 	pid = fork();
100*29346ab0SDavid van Moolenbroek 
101*29346ab0SDavid van Moolenbroek 	switch (pid) {
102*29346ab0SDavid van Moolenbroek 	case -1:
103*29346ab0SDavid van Moolenbroek 		e(0);
104*29346ab0SDavid van Moolenbroek 		break;
105*29346ab0SDavid van Moolenbroek 	case 0:
106*29346ab0SDavid van Moolenbroek 		if (mode != 0)
107*29346ab0SDavid van Moolenbroek 			spin();
108*29346ab0SDavid van Moolenbroek 		exit(0);
109*29346ab0SDavid van Moolenbroek 	default:
110*29346ab0SDavid van Moolenbroek 		if (mode == 0)
111*29346ab0SDavid van Moolenbroek 			sleep(1);
112*29346ab0SDavid van Moolenbroek 
113*29346ab0SDavid van Moolenbroek 		if (mode != 2) {
114*29346ab0SDavid van Moolenbroek 			/*
115*29346ab0SDavid van Moolenbroek 			 * Try with a bad pointer.  This call may fail only
116*29346ab0SDavid van Moolenbroek 			 * once the child has exited, but it must not clean up
117*29346ab0SDavid van Moolenbroek 			 * the child.
118*29346ab0SDavid van Moolenbroek 			 */
119*29346ab0SDavid van Moolenbroek 			if (wait4(-1, &status, 0, bad_ptr) != -1) e(0);
120*29346ab0SDavid van Moolenbroek 			if (errno != EFAULT) e(0);
121*29346ab0SDavid van Moolenbroek 		}
122*29346ab0SDavid van Moolenbroek 
123*29346ab0SDavid van Moolenbroek 		r_usage.ru_nsignals = 1234; /* see if it's written at all */
124*29346ab0SDavid van Moolenbroek 
125*29346ab0SDavid van Moolenbroek 		/* Wait for the actual process. */
126*29346ab0SDavid van Moolenbroek 		if (wait4(-1, &status, 0, &r_usage) != pid) e(0);
127*29346ab0SDavid van Moolenbroek 		if (!WIFEXITED(status)) e(0);
128*29346ab0SDavid van Moolenbroek 		if (WEXITSTATUS(status) != 0) e(0);
129*29346ab0SDavid van Moolenbroek 
130*29346ab0SDavid van Moolenbroek 		if (r_usage.ru_nsignals != 0) e(0);
131*29346ab0SDavid van Moolenbroek 
132*29346ab0SDavid van Moolenbroek 		/* Only check for actual time spent if the child spun. */
133*29346ab0SDavid van Moolenbroek 		if (mode != 0)
134*29346ab0SDavid van Moolenbroek 			CHECK_NOT_ZERO_FIELD(r_usage, ru_utime.tv_sec);
135*29346ab0SDavid van Moolenbroek 	}
136*29346ab0SDavid van Moolenbroek }
137*29346ab0SDavid van Moolenbroek 
138*29346ab0SDavid van Moolenbroek /*
139*29346ab0SDavid van Moolenbroek  * Test wait4().
140*29346ab0SDavid van Moolenbroek  */
141*29346ab0SDavid van Moolenbroek static void
test75b(void)142*29346ab0SDavid van Moolenbroek test75b(void)
143*29346ab0SDavid van Moolenbroek {
144*29346ab0SDavid van Moolenbroek 	void *ptr;
145*29346ab0SDavid van Moolenbroek 
146*29346ab0SDavid van Moolenbroek 	if ((ptr = mmap(NULL, sizeof(struct rusage), PROT_READ,
147*29346ab0SDavid van Moolenbroek 	    MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) e(0);
148*29346ab0SDavid van Moolenbroek 	if (munmap(ptr, sizeof(struct rusage)) != 0) e(0);
149*29346ab0SDavid van Moolenbroek 	/* "ptr" is now a known-bad pointer */
150*29346ab0SDavid van Moolenbroek 
151*29346ab0SDavid van Moolenbroek 	sub75b(0, ptr);
152*29346ab0SDavid van Moolenbroek 	sub75b(1, ptr);
153*29346ab0SDavid van Moolenbroek 	sub75b(2, NULL);
154*29346ab0SDavid van Moolenbroek }
155*29346ab0SDavid van Moolenbroek 
156*29346ab0SDavid van Moolenbroek int
main(int argc,char * argv[])157*29346ab0SDavid van Moolenbroek main(int argc, char *argv[])
158*29346ab0SDavid van Moolenbroek {
159*29346ab0SDavid van Moolenbroek 
160*29346ab0SDavid van Moolenbroek 	start(75);
161*29346ab0SDavid van Moolenbroek 
162*29346ab0SDavid van Moolenbroek 	test75a();
163*29346ab0SDavid van Moolenbroek 	test75b();
164*29346ab0SDavid van Moolenbroek 
165433d6423SLionel Sambuc 	quit();
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc 	return 0;
168433d6423SLionel Sambuc }
169