From: Bijan Tabatabai <bijan311@xxxxxxxxx> When the -F flag is used in trace-cmd record, trace-cmd stops recording when the executable it is tracing terminates. This patch makes the -P flag act similarly. Signed-off-by: Bijan Tabatabai <bijan311@xxxxxxxxx> --- This patch has changed to use the pidfd interface to determine if a process has ended. It also has changed to work with the patch "trace-cmd: Handle filtered PIDs per ftarce instance" (5502bcef0f962cda). --- tracecmd/include/trace-local.h | 2 + tracecmd/trace-record.c | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/tracecmd/include/trace-local.h b/tracecmd/include/trace-local.h index 4c6a63d..5d58550 100644 --- a/tracecmd/include/trace-local.h +++ b/tracecmd/include/trace-local.h @@ -215,9 +215,11 @@ struct buffer_instance { struct opt_list *options; struct filter_pids *filter_pids; + struct filter_pids *process_pids; char *common_pid_filter; int nr_filter_pids; int len_filter_pids; + int nr_process_pids; bool ptrace_child; int have_set_event_pid; diff --git a/tracecmd/trace-record.c b/tracecmd/trace-record.c index d0619ba..51e9103 100644 --- a/tracecmd/trace-record.c +++ b/tracecmd/trace-record.c @@ -16,6 +16,7 @@ #include <sys/time.h> #include <sys/wait.h> #include <sys/socket.h> +#include <sys/syscall.h> #include <sys/utsname.h> #ifndef NO_PTRACE #include <sys/ptrace.h> @@ -33,6 +34,7 @@ #include <errno.h> #include <limits.h> #include <libgen.h> +#include <poll.h> #include <pwd.h> #include <grp.h> #ifdef VSOCK @@ -1230,6 +1232,81 @@ static pid_t trace_waitpid(enum trace_type type, pid_t pid, int *status, int opt trace_stream_read(pids, recorder_threads, &tv); } while (1); } + +#ifndef __NR_pidfd_open +#define __NR_pidfd_open 434 +#endif + +static int pidfd_open(pid_t pid, unsigned int flags) { + return syscall(__NR_pidfd_open, pid, flags); +} + +static int trace_waitpidfd(id_t pidfd) { + struct pollfd pollfd; + + pollfd.fd = pidfd; + pollfd.events = POLLIN; + + while (!finished) { + int ret = poll(&pollfd, 1, -1); + /* If waitid was interrupted, keep waiting */ + if (ret < 0 && errno == EINTR) + continue; + else if (ret < 0) + return 1; + else + break; + } + + return 0; +} + +static int trace_wait_for_processes(struct buffer_instance *instance) { + int ret = 0; + int nr_fds = 0; + int i; + int *pidfds; + struct filter_pids *pid; + + pidfds = malloc(sizeof(int) * instance->nr_process_pids); + if (!pidfds) + return 1; + + for (pid = instance->process_pids; + pid && instance->nr_process_pids; + pid = pid->next) { + if (pid->exclude) { + instance->nr_process_pids--; + continue; + } + pidfds[nr_fds] = pidfd_open(pid->pid, 0); + + /* If the pid doesn't exist, the process has probably exited */ + if (pidfds[nr_fds] < 0 && errno == ESRCH) { + instance->nr_process_pids--; + continue; + } else if (pidfds[nr_fds] < 0) { + ret = 1; + goto out; + } + + nr_fds++; + instance->nr_process_pids--; + } + + for (i = 0; i < nr_fds; i++) { + if (trace_waitpidfd(pidfds[i])) { + ret = 1; + goto out; + } + } + +out: + for (i = 0; i < nr_fds; i++) + close(pidfds[i]); + free(pidfds); + return ret; +} #ifndef NO_PTRACE /** @@ -5866,7 +5943,9 @@ static void parse_record_options(int argc, fpids_count += add_filter_pid(ctx->instance, atoi(pid), 0); pid = strtok_r(NULL, ",", &sav); + ctx->instance->nr_process_pids++; } + ctx->instance->process_pids = ctx->instance->filter_pids; free(pids); break; case 'c': @@ -6361,6 +6440,11 @@ static void record_trace(int argc, char **argv, } /* sleep till we are woken with Ctrl^C */ printf("Hit Ctrl^C to stop recording\n"); + for_all_instances(instance) { + if (instance->nr_process_pids + && !trace_wait_for_processes(instance)) + finished = 1; + } while (!finished) trace_or_sleep(type, pwait); } -- 2.25.1