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