xref: /minix/minix/tests/test75.c (revision 9f988b79)
1 /* Test 75 - getrusage and wait4 test.
2  */
3 
4 #include <sys/resource.h>
5 #include <sys/time.h>
6 #include <stdio.h>
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <sys/mman.h>
11 #include <unistd.h>
12 
13 #include "common.h"
14 
15 #define CHECK_ZERO_FIELD(rusage, field)		\
16 	if (rusage.field != 0)			\
17 		em(1, #field " must be zero");
18 
19 #define CHECK_NOT_ZERO_FIELD(rusage, field)	\
20 	if (rusage.field == 0)			\
21 		em(1, #field " can't be zero");
22 
23 #define CHECK_EQUAL_FIELD(rusage1, rusage2, field)		  \
24 	if (rusage1.field != rusage2.field)			  \
25 		em(1, #field " of " #rusage1 " doesn't equal to " \
26 			#field " of " #rusage2);
27 
28 static void
29 spin(void)
30 {
31 	struct timeval start_time;
32 	struct timeval end_time;
33 	unsigned int loop = 0;
34 	if (gettimeofday(&start_time, NULL) == -1) e(1);
35 	end_time = start_time;
36 	do {
37 		if ((++loop % 3000000000) == 0) {
38 			if (gettimeofday(&end_time, NULL) == -1) e(1);
39 		}
40 	} while (start_time.tv_sec + 10 > end_time.tv_sec);
41 }
42 
43 /*
44  * Test getrusage(2).
45  */
46 static void
47 test75a(void)
48 {
49 	struct rusage r_usage1;
50 	struct rusage r_usage2;
51 	struct rusage r_usage3;
52 	pid_t child;
53 	int status = 0;
54 
55 	if ((getrusage(RUSAGE_SELF + 1, &r_usage1) != -1 || errno != EINVAL) ||
56 	    (getrusage(RUSAGE_CHILDREN - 1, &r_usage1) != -1 ||
57 	     errno != EINVAL) || (getrusage(RUSAGE_SELF, NULL) != -1 ||
58 	     errno != EFAULT))
59 		e(1);
60 
61 	spin();
62 	if (getrusage(RUSAGE_SELF, &r_usage1) != 0) e(1);
63 	CHECK_NOT_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
64 	CHECK_NOT_ZERO_FIELD(r_usage1, ru_maxrss);
65 	if (getrusage(RUSAGE_CHILDREN, &r_usage2) != 0) e(1);
66 
67 	if ((child = fork()) == 0) {
68 		/*
69 		 * We cannot do this part of the test in the parent, since
70 		 * start() calls system() which spawns a child process.
71 		 */
72 		if (getrusage(RUSAGE_CHILDREN, &r_usage1) != 0) e(1);
73 		CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_sec);
74 		CHECK_ZERO_FIELD(r_usage1, ru_utime.tv_usec);
75 		spin();
76 		exit(errct);
77 	} else {
78 		if (child != waitpid(child, &status, 0)) e(1);
79 		if (WEXITSTATUS(status) != 0) e(1);
80 		if (getrusage(RUSAGE_CHILDREN, &r_usage3) != 0) e(1);
81 		CHECK_NOT_ZERO_FIELD(r_usage3, ru_utime.tv_sec);
82 	}
83 }
84 
85 /*
86  * Test the wait4 system call with good and bad rusage pointers, and with the
87  * wait4 either being satisfied immediately or blocking until the child exits:
88  * - mode 0: child has exited when parent calls wait4;
89  * - mode 1: parent blocks waiting for child, using a bad rusage pointer;
90  * - mode 2: parent blocks waiting for child, using a good rusage pointer.
91  */
92 static void
93 sub75b(int mode, void * bad_ptr)
94 {
95 	struct rusage r_usage;
96 	pid_t pid;
97 	int status;
98 
99 	pid = fork();
100 
101 	switch (pid) {
102 	case -1:
103 		e(0);
104 		break;
105 	case 0:
106 		if (mode != 0)
107 			spin();
108 		exit(0);
109 	default:
110 		if (mode == 0)
111 			sleep(1);
112 
113 		if (mode != 2) {
114 			/*
115 			 * Try with a bad pointer.  This call may fail only
116 			 * once the child has exited, but it must not clean up
117 			 * the child.
118 			 */
119 			if (wait4(-1, &status, 0, bad_ptr) != -1) e(0);
120 			if (errno != EFAULT) e(0);
121 		}
122 
123 		r_usage.ru_nsignals = 1234; /* see if it's written at all */
124 
125 		/* Wait for the actual process. */
126 		if (wait4(-1, &status, 0, &r_usage) != pid) e(0);
127 		if (!WIFEXITED(status)) e(0);
128 		if (WEXITSTATUS(status) != 0) e(0);
129 
130 		if (r_usage.ru_nsignals != 0) e(0);
131 
132 		/* Only check for actual time spent if the child spun. */
133 		if (mode != 0)
134 			CHECK_NOT_ZERO_FIELD(r_usage, ru_utime.tv_sec);
135 	}
136 }
137 
138 /*
139  * Test wait4().
140  */
141 static void
142 test75b(void)
143 {
144 	void *ptr;
145 
146 	if ((ptr = mmap(NULL, sizeof(struct rusage), PROT_READ,
147 	    MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) e(0);
148 	if (munmap(ptr, sizeof(struct rusage)) != 0) e(0);
149 	/* "ptr" is now a known-bad pointer */
150 
151 	sub75b(0, ptr);
152 	sub75b(1, ptr);
153 	sub75b(2, NULL);
154 }
155 
156 int
157 main(int argc, char *argv[])
158 {
159 
160 	start(75);
161 
162 	test75a();
163 	test75b();
164 
165 	quit();
166 
167 	return 0;
168 }
169