mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
perf daemon: Force waipid for all session on SIGCHLD delivery
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 <irogers@google.com> Signed-off-by: Jiri Olsa <jolsa@kernel.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Michael Petlan <mpetlan@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lore.kernel.org/lkml/20210320221013.1619613-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
1a096ae46e
commit
1833b64fee
@ -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 != (int) si.ssi_pid)
|
||||
if (session->pid == -1)
|
||||
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);
|
||||
}
|
||||
pid = waitpid(session->pid, &status, WNOHANG);
|
||||
if (pid <= 0)
|
||||
continue;
|
||||
|
||||
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;
|
||||
@ -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);
|
||||
@ -452,7 +458,7 @@ 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;
|
||||
@ -460,7 +466,7 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
|
||||
|
||||
if (start + secs < time(NULL))
|
||||
return -1;
|
||||
} while (wpid != pid);
|
||||
} while (session->pid != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1344,7 +1350,7 @@ out:
|
||||
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");
|
||||
|
Loading…
Reference in New Issue
Block a user