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