Skip to content

Commit 1833b64

Browse files
olsajiriacmel
authored andcommitted
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 <[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]>
1 parent 1a096ae commit 1833b64

File tree

1 file changed

+28
-22
lines changed

1 file changed

+28
-22
lines changed

tools/perf/builtin-daemon.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -402,35 +402,42 @@ static pid_t handle_signalfd(struct daemon *daemon)
402402
int status;
403403
pid_t pid;
404404

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

409417
list_for_each_entry(session, &daemon->sessions, list) {
418+
if (session->pid == -1)
419+
continue;
410420

411-
if (session->pid != (int) si.ssi_pid)
421+
pid = waitpid(session->pid, &status, WNOHANG);
422+
if (pid <= 0)
412423
continue;
413424

414-
pid = waitpid(session->pid, &status, 0);
415-
if (pid == session->pid) {
416-
if (WIFEXITED(status)) {
417-
pr_info("session '%s' exited, status=%d\n",
418-
session->name, WEXITSTATUS(status));
419-
} else if (WIFSIGNALED(status)) {
420-
pr_info("session '%s' killed (signal %d)\n",
421-
session->name, WTERMSIG(status));
422-
} else if (WIFSTOPPED(status)) {
423-
pr_info("session '%s' stopped (signal %d)\n",
424-
session->name, WSTOPSIG(status));
425-
} else {
426-
pr_info("session '%s' Unexpected status (0x%x)\n",
427-
session->name, status);
428-
}
425+
if (WIFEXITED(status)) {
426+
pr_info("session '%s' exited, status=%d\n",
427+
session->name, WEXITSTATUS(status));
428+
} else if (WIFSIGNALED(status)) {
429+
pr_info("session '%s' killed (signal %d)\n",
430+
session->name, WTERMSIG(status));
431+
} else if (WIFSTOPPED(status)) {
432+
pr_info("session '%s' stopped (signal %d)\n",
433+
session->name, WSTOPSIG(status));
434+
} else {
435+
pr_info("session '%s' Unexpected status (0x%x)\n",
436+
session->name, status);
429437
}
430438

431439
session->state = KILL;
432440
session->pid = -1;
433-
return pid;
434441
}
435442

436443
return 0;
@@ -443,7 +450,6 @@ static int daemon_session__wait(struct daemon_session *session, struct daemon *d
443450
.fd = daemon->signal_fd,
444451
.events = POLLIN,
445452
};
446-
pid_t wpid = 0, pid = session->pid;
447453
time_t start;
448454

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

454460
if (err > 0) {
455-
wpid = handle_signalfd(daemon);
461+
handle_signalfd(daemon);
456462
} else if (err < 0) {
457463
perror("failed: poll\n");
458464
return -1;
459465
}
460466

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

465471
return 0;
466472
}
@@ -1344,7 +1350,7 @@ static int __cmd_start(struct daemon *daemon, struct option parent_options[],
13441350
close(sock_fd);
13451351
if (conf_fd != -1)
13461352
close(conf_fd);
1347-
if (conf_fd != -1)
1353+
if (signal_fd != -1)
13481354
close(signal_fd);
13491355

13501356
pr_info("daemon exited\n");

0 commit comments

Comments
 (0)