зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1814551 - Try waiting for child processes directly when the fork server is in use. r=nika
When the fork server is enabled, not all IPC child processes are children of the fork server; currently, process types other than content processes are still spawned directly. This means that we need to `waitid` or `waitpid` them when they exit in order to not leak zombie processes. Specifically, we can just try to `waitid` the process, and then if that fails with `ECHILD` we can assume it was a fork server child and fall back to the previous `kill(pid, 0)` workaround. This patch does that, but only if the fork server is active; otherwise we maintain the current behavior of only waiting for child processes directly. Differential Revision: https://phabricator.services.mozilla.com/D168756
This commit is contained in:
Родитель
f0b145fdd2
Коммит
e38f0ca71d
|
@ -30,6 +30,7 @@
|
|||
#include "base/dir_reader_posix.h"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
// For PR_DuplicateEnvironment:
|
||||
#include "prenv.h"
|
||||
#include "prmem.h"
|
||||
|
@ -196,20 +197,25 @@ void CloseSuperfluousFds(void* aCtx, bool (*aShouldPreserve)(void*, int)) {
|
|||
}
|
||||
|
||||
bool IsProcessDead(ProcessHandle handle, bool blocking) {
|
||||
auto handleForkServer = [handle]() -> mozilla::Maybe<bool> {
|
||||
#ifdef MOZ_ENABLE_FORKSERVER
|
||||
if (mozilla::ipc::ForkServiceChild::Get()) {
|
||||
// We only know if a process exists, but not if it has crashed.
|
||||
//
|
||||
// Since content processes are not direct children of the chrome
|
||||
// process any more, it is impossible to use |waitpid()| to wait for
|
||||
// them.
|
||||
const int r = kill(handle, 0);
|
||||
// FIXME: for unexpected errors we should probably log a warning
|
||||
// and return true, so that the caller doesn't loop / hang /
|
||||
// try to kill the process. (Bug 1658072 will rewrite this code.)
|
||||
return r < 0 && errno == ESRCH;
|
||||
}
|
||||
if (errno == ECHILD && mozilla::ipc::ForkServiceChild::Get()) {
|
||||
// We only know if a process exists, but not if it has crashed.
|
||||
//
|
||||
// Since content processes are not direct children of the chrome
|
||||
// process any more, it is impossible to use |waitpid()| to wait for
|
||||
// them.
|
||||
const int r = kill(handle, 0);
|
||||
// FIXME: for unexpected errors we should probably log a warning
|
||||
// and return true, so that the caller doesn't loop / hang /
|
||||
// try to kill the process. (Bug 1658072 will rewrite this code.)
|
||||
return mozilla::Some(r < 0 && errno == ESRCH);
|
||||
}
|
||||
#else
|
||||
mozilla::Unused << handle;
|
||||
#endif
|
||||
return mozilla::Nothing();
|
||||
};
|
||||
|
||||
#ifdef HAVE_WAITID
|
||||
|
||||
|
@ -222,6 +228,10 @@ bool IsProcessDead(ProcessHandle handle, bool blocking) {
|
|||
const int wflags = WEXITED | WNOWAIT | (blocking ? 0 : WNOHANG);
|
||||
int result = HANDLE_EINTR(waitid(P_PID, handle, &si, wflags));
|
||||
if (result == -1) {
|
||||
if (auto forkServerReturn = handleForkServer()) {
|
||||
return *forkServerReturn;
|
||||
}
|
||||
|
||||
// This shouldn't happen, but sometimes it does. The error is
|
||||
// probably ECHILD and the reason is probably that a pid was
|
||||
// waited on again after a previous wait reclaimed its zombie.
|
||||
|
@ -287,6 +297,10 @@ bool IsProcessDead(ProcessHandle handle, bool blocking) {
|
|||
int status;
|
||||
const int result = waitpid(handle, &status, blocking ? 0 : WNOHANG);
|
||||
if (result == -1) {
|
||||
if (auto forkServerReturn = handleForkServer()) {
|
||||
return *forkServerReturn;
|
||||
}
|
||||
|
||||
CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle
|
||||
<< " errno:" << errno;
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче