Skip to content

Commit

Permalink
perf daemon: Force waipid for all session on SIGCHLD delivery
Browse files Browse the repository at this point in the history
If we don't process SIGCHLD before another comes, we will see just one
SIGCHLD as a result. In this case current code will miss exit
notification for a session and wait forever.

Adding extra waitpid check for all sessions when SIGCHLD is received, to
make sure we don't miss any session exit.

Also fix close condition for signal_fd.

Reported-by: Ian Rogers <[email protected]>
Signed-off-by: Jiri Olsa <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Michael Petlan <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Link: http://lore.kernel.org/lkml/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
  • Loading branch information
olsajiri authored and acmel committed Mar 24, 2021
1 parent 1a096ae commit 1833b64
Showing 1 changed file with 28 additions and 22 deletions.
50 changes: 28 additions & 22 deletions tools/perf/builtin-daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,35 +402,42 @@ static pid_t handle_signalfd(struct daemon *daemon)
int status;
pid_t pid;

/*
* Take signal fd data as pure signal notification and check all
* the sessions state. The reason is that multiple signals can get
* coalesced in kernel and we can receive only single signal even
* if multiple SIGCHLD were generated.
*/
err = read(daemon->signal_fd, &si, sizeof(struct signalfd_siginfo));
if (err != sizeof(struct signalfd_siginfo))
if (err != sizeof(struct signalfd_siginfo)) {
pr_err("failed to read signal fd\n");
return -1;
}

list_for_each_entry(session, &daemon->sessions, list) {
if (session->pid == -1)
continue;

if (session->pid != (int) si.ssi_pid)
pid = waitpid(session->pid, &status, WNOHANG);
if (pid <= 0)
continue;

pid = waitpid(session->pid, &status, 0);
if (pid == session->pid) {
if (WIFEXITED(status)) {
pr_info("session '%s' exited, status=%d\n",
session->name, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
pr_info("session '%s' killed (signal %d)\n",
session->name, WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
pr_info("session '%s' stopped (signal %d)\n",
session->name, WSTOPSIG(status));
} else {
pr_info("session '%s' Unexpected status (0x%x)\n",
session->name, status);
}
if (WIFEXITED(status)) {
pr_info("session '%s' exited, status=%d\n",
session->name, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
pr_info("session '%s' killed (signal %d)\n",
session->name, WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
pr_info("session '%s' stopped (signal %d)\n",
session->name, WSTOPSIG(status));
} else {
pr_info("session '%s' Unexpected status (0x%x)\n",
session->name, status);
}

session->state = KILL;
session->pid = -1;
return pid;
}

return 0;
Expand All @@ -443,7 +450,6 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
.fd = daemon->signal_fd,
.events = POLLIN,
};
pid_t wpid = 0, pid = session->pid;
time_t start;

start = time(NULL);
Expand All @@ -452,15 +458,15 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
int err = poll(&pollfd, 1, 1000);

if (err > 0) {
wpid = handle_signalfd(daemon);
handle_signalfd(daemon);
} else if (err < 0) {
perror("failed: poll\n");
return -1;
}

if (start + secs < time(NULL))
return -1;
} while (wpid != pid);
} while (session->pid != -1);

return 0;
}
Expand Down Expand Up @@ -1344,7 +1350,7 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
close(sock_fd);
if (conf_fd != -1)
close(conf_fd);
if (conf_fd != -1)
if (signal_fd != -1)
close(signal_fd);

pr_info("daemon exited\n");
Expand Down

0 comments on commit 1833b64

Please sign in to comment.