diff -ur strace-5.5/delay.h strace-5.5.x/delay.h --- strace-5.5/delay.h 2019-08-06 15:38:20.000000000 +0200 +++ strace-5.5.x/delay.h 2020-02-29 12:39:51.563110827 +0100 @@ -14,5 +14,6 @@ void delay_timer_expired(void); void arm_delay_timer(const struct tcb *); void delay_tcb(struct tcb *, uint16_t delay_idx, bool isenter); +int my_waitpid(int, int*, int); #endif /* !STRACE_DELAY_H */ diff -ur strace-5.5/filter_seccomp.c strace-5.5.x/filter_seccomp.c --- strace-5.5/filter_seccomp.c 2020-02-06 16:16:17.000000000 +0100 +++ strace-5.5.x/filter_seccomp.c 2020-02-29 12:42:43.184120263 +0100 @@ -19,6 +19,7 @@ #include "number_set.h" #include "syscall.h" #include "scno.h" +#include "delay.h" bool seccomp_filtering; bool seccomp_before_sysentry; @@ -136,7 +137,7 @@ int status; for (;;) { - long rc = waitpid(pid, &status, 0); + long rc = my_waitpid(pid, &status, 0); if (rc < 0 && errno == EINTR) continue; if (rc == pid) @@ -272,7 +273,7 @@ if (pid) { kill(pid, SIGKILL); for (;;) { - long rc = waitpid(pid, NULL, 0); + long rc = my_waitpid(pid, NULL, 0); if (rc < 0 && errno == EINTR) continue; break; diff -ur strace-5.5/Makefile.am strace-5.5.x/Makefile.am --- strace-5.5/Makefile.am 2020-02-06 16:16:17.000000000 +0100 +++ strace-5.5.x/Makefile.am 2020-02-29 10:28:04.515676065 +0100 @@ -45,7 +45,7 @@ strace_CPPFLAGS = $(AM_CPPFLAGS) strace_CFLAGS = $(AM_CFLAGS) strace_LDFLAGS = -strace_LDADD = libstrace.a $(clock_LIBS) $(timer_LIBS) +strace_LDADD = libstrace.a -lpthread $(clock_LIBS) $(timer_LIBS) noinst_LIBRARIES = libstrace.a libstrace_a_CPPFLAGS = $(strace_CPPFLAGS) diff -ur strace-5.5/Makefile.in strace-5.5.x/Makefile.in --- strace-5.5/Makefile.in 2020-02-06 17:23:35.000000000 +0100 +++ strace-5.5.x/Makefile.in 2020-02-29 10:28:28.833677402 +0100 @@ -1631,7 +1631,7 @@ $(am__append_11) $(CODE_COVERAGE_CPPFLAGS) strace_CFLAGS = $(AM_CFLAGS) $(am__append_4) $(CODE_COVERAGE_CFLAGS) strace_LDFLAGS = $(am__append_5) $(am__append_9) $(am__append_12) -strace_LDADD = libstrace.a $(clock_LIBS) $(timer_LIBS) $(am__append_6) \ +strace_LDADD = libstrace.a -lpthread $(clock_LIBS) $(timer_LIBS) $(am__append_6) \ $(am__append_10) $(am__append_13) $(CODE_COVERAGE_LIBS) \ $(am__append_14) $(am__append_18) noinst_LIBRARIES = libstrace.a $(am__append_15) $(am__append_19) diff -ur strace-5.5/ptrace_syscall_info.c strace-5.5.x/ptrace_syscall_info.c --- strace-5.5/ptrace_syscall_info.c 2020-02-06 16:16:17.000000000 +0100 +++ strace-5.5.x/ptrace_syscall_info.c 2020-02-29 12:41:44.565117040 +0100 @@ -12,6 +12,7 @@ #include "ptrace.h" #include "ptrace_syscall_info.h" #include "scno.h" +#include "delay.h" #include #include @@ -118,7 +119,7 @@ }; const size_t size = sizeof(info); int status; - long rc = waitpid(pid, &status, 0); + long rc = my_waitpid(pid, &status, 0); if (rc != pid) { /* cannot happen */ kill_tracee(pid); @@ -247,7 +248,7 @@ done: if (pid) { kill_tracee(pid); - waitpid(pid, NULL, 0); + my_waitpid(pid, NULL, 0); ptrace_stop = -1U; } diff -ur strace-5.5/strace.c strace-5.5.x/strace.c --- strace-5.5/strace.c 2020-02-06 16:16:17.000000000 +0100 +++ strace-5.5.x/strace.c 2020-03-01 07:53:27.028407698 +0100 @@ -15,6 +15,7 @@ #include #include "ptrace.h" #include +#include #include #include #ifdef HAVE_PATHS_H @@ -1002,7 +1003,7 @@ */ for (;;) { unsigned int sig; - if (waitpid(tcp->pid, &status, __WALL) < 0) { + if (my_waitpid(tcp->pid, &status, __WALL) < 0) { if (errno == EINTR) continue; /* @@ -1615,7 +1616,7 @@ int status, tracee_pid; errno = 0; - tracee_pid = waitpid(pid, &status, 0); + tracee_pid = my_waitpid(pid, &status, 0); if (tracee_pid <= 0) { if (errno == EINTR) continue; @@ -1663,6 +1664,69 @@ sigaction(signo, &sa, oldact); } +#define MAX_WAITIDX 65536 +static unsigned short in_idx = 0, out_idx = 0; +static sem_t wait_sem; +static int wait_pid[MAX_WAITIDX]; +static int wait_status[MAX_WAITIDX]; +static struct rusage wait_rusage[MAX_WAITIDX]; + +static void +child_sighandler(int sig) +{ + int old_errno = errno; + int status; + struct rusage ru; + int pid = wait4(-1, &status, __WALL | WNOHANG, (cflag ? &ru : NULL)); + + if (pid > 0) { + if (WIFSTOPPED(status) && (status >> 16) == PTRACE_EVENT_EXIT) + ptrace(PTRACE_SYSCALL, pid, 0L, 0L); + wait_pid[in_idx] = pid; + wait_status[in_idx] = status; + if (cflag) + wait_rusage[in_idx] = ru; + in_idx++; + if (in_idx == out_idx || sem_post(&wait_sem) == -1) + { + const char *msg = "fatal error in child_sighandler\n"; + status = write(STDERR_FILENO, msg, strlen(msg)); + _exit(2); + } + } + + errno = old_errno; +} + +int my_waitpid(int pid, int *status, int options) +{ + int skip = 0; + unsigned short idx = out_idx; + for (;;) { + while (sem_wait(&wait_sem) == -1 && errno == EINTR) + ; + if (wait_pid[idx] == pid) + break; + idx++; + skip++; + } + *status = wait_status[idx]; + while (skip > 0) { + unsigned short idx1 = idx; + idx1--; + wait_status[idx] = wait_status[idx1]; + wait_pid[idx] = wait_pid[idx1]; + if (cflag) + wait_rusage[idx] = wait_rusage[idx1]; + if (sem_post(&wait_sem) == -1) + error_msg_and_die("fatal error in my_waitpid"); + skip--; + idx--; + } + out_idx++; + return pid; +} + /* * Initialization part of main() was eating much stack (~0.5k), * which was unused after init. @@ -2015,7 +2079,9 @@ memset(acolumn_spaces, ' ', acolumn); acolumn_spaces[acolumn] = '\0'; - set_sighandler(SIGCHLD, SIG_DFL, ¶ms_for_tracee.child_sa); + if (sem_init(&wait_sem, 0, 0) == -1) + perror_msg_and_die("Unable to initialize signal wait sema"); + set_sighandler(SIGCHLD, child_sighandler, ¶ms_for_tracee.child_sa); #ifdef ENABLE_STACKTRACE if (stack_trace_enabled) @@ -2607,10 +2673,28 @@ * then the system call will be interrupted and * the expiration will be handled by the signal handler. */ - int status; + int status = 0; struct rusage ru; - int pid = wait4(-1, &status, __WALL, (cflag ? &ru : NULL)); - int wait_errno = errno; + int pid = 0; + int wait_errno = 0; + if (in_idx == out_idx) { + pid = wait4(-1, &status, __WALL | WNOHANG, (cflag ? &ru : NULL)); + wait_errno = errno; + if (pid > 0 && WIFSTOPPED(status) && (status >> 16) == PTRACE_EVENT_EXIT) + ptrace(PTRACE_SYSCALL, pid, 0L, 0L); + } + if (pid == 0) { + while (sem_wait(&wait_sem) == -1 && errno == EINTR) + ; + + if (in_idx == out_idx) + error_msg_and_die("wait queue error"); + pid = wait_pid[out_idx]; + status = wait_status[out_idx]; + if (cflag) + ru = wait_rusage[out_idx]; + out_idx++; + } /* * The window of opportunity to handle expirations @@ -2791,8 +2875,17 @@ break; next_event_wait_next: - pid = wait4(-1, &status, __WALL | WNOHANG, (cflag ? &ru : NULL)); - wait_errno = errno; + pid = 0; + if (in_idx != out_idx) { + while (sem_wait(&wait_sem) == -1 && errno == EINTR) + ; + + pid = wait_pid[out_idx]; + status = wait_status[out_idx]; + if (cflag) + ru = wait_rusage[out_idx]; + out_idx++; + } wait_nohang = true; } @@ -3019,7 +3112,7 @@ case TE_STOP_BEFORE_EXIT: print_event_exit(current_tcp); - break; + return true; } /* We handled quick cases, we are permitted to interrupt now. */ @@ -3138,7 +3231,7 @@ if (shared_log != stderr) fclose(shared_log); if (popen_pid) { - while (waitpid(popen_pid, NULL, 0) < 0 && errno == EINTR) + while (my_waitpid(popen_pid, NULL, 0) < 0 && errno == EINTR) ; } if (sig) {