From 2bcc9f1058ffe87870de2e910b5e7b96ad9ffd0b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 25 Dec 2023 11:31:36 -0800 Subject: [PATCH] record: Use pipe instead of eventfd It uses an eventfd to sync parent and child to setup environment before starting the actual tracing. But it seems eventfd cannot handle the case where the parent existed early. In that case child will be stuck on the eventfd waiting for someone to write. The pipe will reject such case (IOW read will return an error) because it has clear role for each fd while an eventfd can be used for read and write so it won't reject read without writers. Fixed: #1866 Signed-off-by: Namhyung Kim --- cmds/record.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cmds/record.c b/cmds/record.c index 81de11afc..0389c58c5 100644 --- a/cmds/record.c +++ b/cmds/record.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -1835,7 +1834,7 @@ static void setup_writers(struct writer_data *wd, struct uftrace_opts *opts) wd->writers = xmalloc(opts->nr_thread * sizeof(*wd->writers)); if (pipe(thread_ctl) < 0) - pr_err("cannot create an eventfd for writer thread"); + pr_err("cannot create a pipe for writer thread"); } static void start_tracing(struct writer_data *wd, struct uftrace_opts *opts, int ready_fd) @@ -2078,16 +2077,17 @@ static void write_symbol_files(struct writer_data *wd, struct uftrace_opts *opts chown_directory(opts->dirname); } -int do_main_loop(int ready, struct uftrace_opts *opts, int pid) +static int do_main_loop(int ready[], struct uftrace_opts *opts, int pid) { int ret; struct writer_data wd; char *channel = NULL; + close(ready[0]); if (opts->nop) { setup_writers(&wd, opts); - start_tracing(&wd, opts, ready); - close(ready); + start_tracing(&wd, opts, ready[1]); + close(ready[1]); wait(NULL); uftrace_done = true; @@ -2110,8 +2110,8 @@ int do_main_loop(int ready, struct uftrace_opts *opts, int pid) pr_out("uftrace: install signal handlers to task %d\n", pid); setup_writers(&wd, opts); - start_tracing(&wd, opts, ready); - close(ready); + start_tracing(&wd, opts, ready[1]); + close(ready[1]); while (!uftrace_done) { struct pollfd pollfd = { @@ -2139,7 +2139,7 @@ int do_main_loop(int ready, struct uftrace_opts *opts, int pid) return ret; } -int do_child_exec(int ready, struct uftrace_opts *opts, int argc, char *argv[]) +static int do_child_exec(int ready[], struct uftrace_opts *opts, int argc, char *argv[]) { uint64_t dummy; char *shebang = NULL; @@ -2148,6 +2148,7 @@ int do_child_exec(int ready, struct uftrace_opts *opts, int argc, char *argv[]) struct strv new_args = STRV_INIT; bool is_python = false; + close(ready[1]); if (opts->no_randomize_addr) { /* disable ASLR (Address Space Layout Randomization) */ if (personality(ADDR_NO_RANDOMIZE) < 0) @@ -2223,8 +2224,9 @@ int do_child_exec(int ready, struct uftrace_opts *opts, int argc, char *argv[]) setup_child_environ(opts, argc, argv); /* wait for parent ready */ - if (read(ready, &dummy, sizeof(dummy)) != (ssize_t)sizeof(dummy)) + if (read(ready[0], &dummy, sizeof(dummy)) != (ssize_t)sizeof(dummy)) pr_err("waiting for parent failed"); + close(ready[0]); if (is_python) { char *python_path = NULL; @@ -2257,7 +2259,7 @@ int do_child_exec(int ready, struct uftrace_opts *opts, int argc, char *argv[]) int command_record(int argc, char *argv[], struct uftrace_opts *opts) { int pid; - int ready; + int ready[2]; int ret = -1; char *channel = NULL; @@ -2279,9 +2281,8 @@ int command_record(int argc, char *argv[], struct uftrace_opts *opts) fflush(stdout); - ready = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE); - if (ready < 0) - pr_dbg("creating eventfd failed: %d\n", ready); + if (pipe(ready) < 0) + pr_err("creating pipe failed"); pid = fork(); if (pid < 0)