]> granicus.if.org Git - strace/blob - tests/wait4.c
strace: terminate itself if interrupted by a signal
[strace] / tests / wait4.c
1 /*
2  * Check decoding of wait4 syscall.
3  *
4  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2017 The strace developers.
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "tests.h"
12 #include <assert.h>
13 #include <signal.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <sys/wait.h>
17 #include <sys/resource.h>
18
19 static const char *
20 sprint_rusage(const struct rusage *const ru)
21 {
22         static char buf[1024];
23         snprintf(buf, sizeof(buf),
24                  "{ru_utime={tv_sec=%lld, tv_usec=%llu}"
25                  ", ru_stime={tv_sec=%lld, tv_usec=%llu}"
26 #if VERBOSE
27                  ", ru_maxrss=%lu"
28                  ", ru_ixrss=%lu"
29                  ", ru_idrss=%lu"
30                  ", ru_isrss=%lu"
31                  ", ru_minflt=%lu"
32                  ", ru_majflt=%lu"
33                  ", ru_nswap=%lu"
34                  ", ru_inblock=%lu"
35                  ", ru_oublock=%lu"
36                  ", ru_msgsnd=%lu"
37                  ", ru_msgrcv=%lu"
38                  ", ru_nsignals=%lu"
39                  ", ru_nvcsw=%lu"
40                  ", ru_nivcsw=%lu}"
41 #else
42                  ", ...}"
43 #endif
44                  , (long long) ru->ru_utime.tv_sec
45                  , zero_extend_signed_to_ull(ru->ru_utime.tv_usec)
46                  , (long long) ru->ru_stime.tv_sec
47                  , zero_extend_signed_to_ull(ru->ru_stime.tv_usec)
48 #if VERBOSE
49                  , (long) ru->ru_maxrss
50                  , (long) ru->ru_ixrss
51                  , (long) ru->ru_idrss
52                  , (long) ru->ru_isrss
53                  , (long) ru->ru_minflt
54                  , (long) ru->ru_majflt
55                  , (long) ru->ru_nswap
56                  , (long) ru->ru_inblock
57                  , (long) ru->ru_oublock
58                  , (long) ru->ru_msgsnd
59                  , (long) ru->ru_msgrcv
60                  , (long) ru->ru_nsignals
61                  , (long) ru->ru_nvcsw
62                  , (long) ru->ru_nivcsw
63 #endif
64                  );
65         return buf;
66 }
67
68 static pid_t
69 do_wait4(pid_t pid, int *wstatus, int options, struct rusage *ru)
70 {
71         sigset_t mask = {};
72         sigaddset(&mask, SIGCHLD);
73
74         assert(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
75         pid_t rc = wait4(pid, wstatus, options, ru);
76         assert(sigprocmask(SIG_UNBLOCK, &mask, NULL) == 0);
77         return rc;
78 }
79
80 int
81 main(void)
82 {
83         tprintf("%s", "");
84
85         int fds[2];
86         if (pipe(fds))
87                 perror_msg_and_fail("pipe");
88
89         pid_t pid;
90         pid = fork();
91         if (pid < 0)
92                 perror_msg_and_fail("fork");
93
94         if (!pid) {
95                 char c;
96                 (void) close(1);
97                 assert(read(0, &c, sizeof(c)) == 1);
98                 return 42;
99         }
100
101         (void) close(0);
102
103         TAIL_ALLOC_OBJECT_CONST_PTR(int, s);
104         if (wait4(pid, s, WNOHANG|__WALL, NULL))
105                 perror_msg_and_fail("wait4 #1");
106         tprintf("wait4(%d, %p, WNOHANG|__WALL, NULL) = 0\n", pid, s);
107
108         TAIL_ALLOC_OBJECT_CONST_PTR(struct rusage, rusage);
109         if (wait4(pid, s, WNOHANG|__WALL, rusage))
110                 perror_msg_and_fail("wait4 #2");
111         tprintf("wait4(%d, %p, WNOHANG|__WALL, %p) = 0\n", pid, s, rusage);
112
113         assert(write(1, "", 1) == 1);
114         (void) close(1);
115
116         assert(do_wait4(pid, s, 0, rusage) == pid);
117         assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 42);
118         tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 42}], 0, %s)"
119                 " = %d\n", pid, sprint_rusage(rusage), pid);
120
121         pid = fork();
122         if (pid < 0)
123                 perror_msg_and_fail("fork");
124
125         if (!pid) {
126                 (void) raise(SIGUSR1);
127                 return 1;
128         }
129
130         assert(do_wait4(pid, s, __WALL, rusage) == pid);
131         assert(WIFSIGNALED(*s) && WTERMSIG(*s) == SIGUSR1);
132         tprintf("wait4(%d, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGUSR1}]"
133                 ", __WALL, %s) = %d\n", pid, sprint_rusage(rusage), pid);
134
135         if (pipe(fds))
136                 perror_msg_and_fail("pipe");
137         pid = fork();
138         if (pid < 0)
139                 perror_msg_and_fail("fork");
140
141         if (!pid) {
142                 (void) close(1);
143                 raise(SIGSTOP);
144                 char c;
145                 assert(read(0, &c, sizeof(c)) == 1);
146                 return 0;
147         }
148
149         (void) close(0);
150
151         assert(do_wait4(pid, s, WSTOPPED, rusage) == pid);
152         assert(WIFSTOPPED(*s) && WSTOPSIG(*s) == SIGSTOP);
153         tprintf("wait4(%d, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGSTOP}]"
154                 ", WSTOPPED, %s) = %d\n", pid, sprint_rusage(rusage), pid);
155
156         if (kill(pid, SIGCONT))
157                 perror_msg_and_fail("kill(SIGCONT)");
158
159 #if defined WCONTINUED && defined WIFCONTINUED
160         assert(do_wait4(pid, s, WCONTINUED, rusage) == pid);
161         assert(WIFCONTINUED(*s));
162         tprintf("wait4(%d, [{WIFCONTINUED(s)}], WCONTINUED"
163                 ", %s) = %d\n", pid, sprint_rusage(rusage), pid);
164 #endif /* WCONTINUED && WIFCONTINUED */
165
166         assert(write(1, "", 1) == 1);
167         (void) close(1);
168
169         assert(do_wait4(pid, s, 0, rusage) == pid);
170         assert(WIFEXITED(*s) && WEXITSTATUS(*s) == 0);
171         tprintf("wait4(%d, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0"
172                 ", %s) = %d\n", pid, sprint_rusage(rusage), pid);
173
174         assert(wait4(-1, s, WNOHANG|WSTOPPED|__WALL, rusage) == -1);
175         tprintf("wait4(-1, %p, WNOHANG|WSTOPPED|__WALL, %p) = -1 %s (%m)\n",
176                 s, rusage, errno2name());
177
178         tprintf("%s\n", "+++ exited with 0 +++");
179         return 0;
180 }