Dmitry V. Levin | 1f68abf | 2016-06-10 09:15:59 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Check decoding of wait4 syscall. |
| 3 | * |
| 4 | * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org> |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in the |
| 14 | * documentation and/or other materials provided with the distribution. |
| 15 | * 3. The name of the author may not be used to endorse or promote products |
| 16 | * derived from this software without specific prior written permission. |
| 17 | * |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | #include "tests.h" |
| 31 | #include <assert.h> |
| 32 | #include <signal.h> |
| 33 | #include <stdio.h> |
| 34 | #include <unistd.h> |
| 35 | #include <sys/wait.h> |
| 36 | #include <sys/resource.h> |
| 37 | |
| 38 | static const char * |
| 39 | sprint_rusage(const struct rusage *const ru) |
| 40 | { |
| 41 | static char buf[1024]; |
| 42 | snprintf(buf, sizeof(buf), |
| 43 | "{ru_utime={%lu, %lu}" |
| 44 | ", ru_stime={%lu, %lu}" |
| 45 | #ifdef VERBOSE_RUSAGE |
| 46 | ", ru_maxrss=%lu" |
| 47 | ", ru_ixrss=%lu" |
| 48 | ", ru_idrss=%lu" |
| 49 | ", ru_isrss=%lu" |
| 50 | ", ru_minflt=%lu" |
| 51 | ", ru_majflt=%lu" |
| 52 | ", ru_nswap=%lu" |
| 53 | ", ru_inblock=%lu" |
| 54 | ", ru_oublock=%lu" |
| 55 | ", ru_msgsnd=%lu" |
| 56 | ", ru_msgrcv=%lu" |
| 57 | ", ru_nsignals=%lu" |
| 58 | ", ru_nvcsw=%lu" |
| 59 | ", ru_nivcsw=%lu}" |
| 60 | #else |
| 61 | ", ...}" |
| 62 | #endif |
| 63 | , (long) ru->ru_utime.tv_sec |
| 64 | , (long) ru->ru_utime.tv_usec |
| 65 | , (long) ru->ru_stime.tv_sec |
| 66 | , (long) ru->ru_stime.tv_usec |
| 67 | #ifdef VERBOSE_RUSAGE |
| 68 | , (long) ru->ru_maxrss |
| 69 | , (long) ru->ru_ixrss |
| 70 | , (long) ru->ru_idrss |
| 71 | , (long) ru->ru_isrss |
| 72 | , (long) ru->ru_minflt |
| 73 | , (long) ru->ru_majflt |
| 74 | , (long) ru->ru_nswap |
| 75 | , (long) ru->ru_inblock |
| 76 | , (long) ru->ru_oublock |
| 77 | , (long) ru->ru_msgsnd |
| 78 | , (long) ru->ru_msgrcv |
| 79 | , (long) ru->ru_nsignals |
| 80 | , (long) ru->ru_nvcsw |
| 81 | , (long) ru->ru_nivcsw |
| 82 | #endif |
| 83 | ); |
| 84 | return buf; |
| 85 | } |
| 86 | |
| 87 | static pid_t |
| 88 | do_wait4(pid_t pid, int *wstatus, int options, struct rusage *ru) |
| 89 | { |
| 90 | sigset_t mask = {}; |
| 91 | sigaddset(&mask, SIGCHLD); |
| 92 | |
| 93 | assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0); |
| 94 | pid_t rc = wait4(pid, wstatus, options, ru); |
| 95 | assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0); |
| 96 | return rc; |
| 97 | } |
| 98 | |
| 99 | int |
| 100 | main(void) |
| 101 | { |
| 102 | tprintf("%s", ""); |
| 103 | |
| 104 | int fds[2]; |
| 105 | if (pipe(fds)) |
| 106 | perror_msg_and_fail("pipe"); |
| 107 | |
| 108 | pid_t pid; |
| 109 | pid = fork(); |
| 110 | if (pid < 0) |
| 111 | perror_msg_and_fail("fork"); |
| 112 | |
| 113 | if (!pid) { |
| 114 | char c; |
| 115 | (void) close(1); |
| 116 | assert(read(0, &c, sizeof(c)) == 1); |
| 117 | return 42; |
| 118 | } |
| 119 | |
| 120 | (void) close(0); |
| 121 | |
| 122 | int *const s = tail_alloc(sizeof(*s)); |
| 123 | if (wait4(pid, s, WNOHANG|__WALL, NULL)) |
| 124 | perror_msg_and_fail("wait4 #1"); |
| 125 | tprintf("wait4(%d, %p, WNOHANG|__WALL, NULL) = 0\n", pid, s); |
| 126 | |
| 127 | struct rusage *const rusage = tail_alloc(sizeof(*rusage)); |
| 128 | if (wait4(pid, s, WNOHANG|__WALL, rusage)) |
| 129 | perror_msg_and_fail("wait4 #2"); |
| 130 | tprintf("wait4(%d, %p, WNOHANG|__WALL, %p) = 0\n", pid, s, rusage); |
| 131 | |
| 132 | assert(write(1, "", 1) == 1); |
| 133 | (void) close(1); |
| 134 | |
| 135 | assert(do_wait4(pid, s, 0, rusage) == pid); |
| 136 | assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 42); |
| 137 | tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 42}], 0, %s)" |
| 138 | " = %d\n", pid, sprint_rusage(rusage), pid); |
| 139 | |
| 140 | pid = fork(); |
| 141 | if (pid < 0) |
| 142 | perror_msg_and_fail("fork"); |
| 143 | |
| 144 | if (!pid) { |
| 145 | (void) raise(SIGUSR1); |
| 146 | return 1; |
| 147 | } |
| 148 | |
| 149 | assert(do_wait4(pid, s, __WALL, rusage) == pid); |
| 150 | assert(WIFSIGNALED(*s) && WTERMSIG(*s) == SIGUSR1); |
| 151 | tprintf("wait4(%d, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGUSR1}]" |
| 152 | ", __WALL, %s) = %d\n", pid, sprint_rusage(rusage), pid); |
| 153 | |
| 154 | if (pipe(fds)) |
| 155 | perror_msg_and_fail("pipe"); |
| 156 | pid = fork(); |
| 157 | if (pid < 0) |
| 158 | perror_msg_and_fail("fork"); |
| 159 | |
| 160 | if (!pid) { |
| 161 | (void) close(1); |
| 162 | raise(SIGSTOP); |
| 163 | char c; |
| 164 | assert(read(0, &c, sizeof(c)) == 1); |
| 165 | return 0; |
| 166 | } |
| 167 | |
| 168 | (void) close(0); |
| 169 | |
| 170 | assert(do_wait4(pid, s, WSTOPPED, rusage) == pid); |
| 171 | assert(WIFSTOPPED(*s) && WSTOPSIG(*s) == SIGSTOP); |
| 172 | tprintf("wait4(%d, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}]" |
| 173 | ", WSTOPPED, %s) = %d\n", pid, sprint_rusage(rusage), pid); |
| 174 | |
| 175 | if (kill(pid, SIGCONT)) |
| 176 | perror_msg_and_fail("kill(SIGCONT)"); |
| 177 | |
| 178 | #if defined WCONTINUED && defined WIFCONTINUED |
| 179 | assert(do_wait4(pid, s, WCONTINUED, rusage) == pid); |
| 180 | assert(WIFCONTINUED(*s)); |
| 181 | tprintf("wait4(%d, [{WIFCONTINUED(s)}], WCONTINUED" |
| 182 | ", %s) = %d\n", pid, sprint_rusage(rusage), pid); |
| 183 | #endif /* WCONTINUED && WIFCONTINUED */ |
| 184 | |
| 185 | assert(write(1, "", 1) == 1); |
| 186 | (void) close(1); |
| 187 | |
| 188 | assert(do_wait4(pid, s, 0, rusage) == pid); |
| 189 | assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 0); |
| 190 | tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0" |
| 191 | ", %s) = %d\n", pid, sprint_rusage(rusage), pid); |
| 192 | |
| 193 | assert(wait4(-1, s, WNOHANG|WSTOPPED|__WALL, rusage) == -1); |
| 194 | tprintf("wait4(-1, %p, WNOHANG|WSTOPPED|__WALL, %p) = -1 %s (%m)\n", |
| 195 | s, rusage, errno2name()); |
| 196 | |
| 197 | tprintf("%s\n", "+++ exited with 0 +++"); |
| 198 | return 0; |
| 199 | } |