Bug 1880590 - Fix benign data race during fork server shutdown. r=nika

There's a race between `ProcessWatcher` checking if the fork server is
in use (via `ForkServiceChild::Get`) and the fork server shutdown path
(`ForkServerLauncher::Observe` calling `StopForkServer`).  The race
seems to be benign, but it causes test failures under TSan.

As a relatively simple fix, this patch changes `ProcessWatcher` to check
an atomic flag which is true if the fork server has ever been run.
(This also means that, in the case where the fork server has been shut
down but some of its child processes are still running, we will continue
to use the `kill(pid, 0)` fallback.)

Differential Revision: https://phabricator.services.mozilla.com/D203077
This commit is contained in:
Jed Davis 2024-03-02 01:44:38 +00:00
Родитель 4963aba94b
Коммит 48864d54a3
3 изменённых файлов: 12 добавлений и 2 удалений

Просмотреть файл

@ -198,7 +198,7 @@ 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 (errno == ECHILD && mozilla::ipc::ForkServiceChild::Get()) {
if (errno == ECHILD && mozilla::ipc::ForkServiceChild::WasUsed()) {
// We only know if a process exists, but not if it has crashed.
//
// Since content processes are not direct children of the chrome

Просмотреть файл

@ -3,11 +3,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ForkServiceChild.h"
#include "ForkServer.h"
#include "mozilla/ipc/IPDLParamTraits.h"
#include "mozilla/Atomics.h"
#include "mozilla/Logging.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/ipc/IPDLParamTraits.h"
#include "mozilla/ipc/ProtocolMessageUtils.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/Services.h"
@ -23,6 +25,7 @@ namespace ipc {
extern LazyLogModule gForkServiceLog;
mozilla::UniquePtr<ForkServiceChild> ForkServiceChild::sForkServiceChild;
Atomic<bool> ForkServiceChild::sForkServiceUsed;
static bool ConfigurePipeFd(int aFd) {
int flags = fcntl(aFd, F_GETFD, 0);
@ -55,6 +58,7 @@ void ForkServiceChild::StartForkServer() {
return;
}
sForkServiceUsed = true;
sForkServiceChild =
mozilla::MakeUnique<ForkServiceChild>(server.release(), subprocess);
}

Просмотреть файл

@ -74,6 +74,11 @@ class ForkServiceChild {
return child == nullptr || child->mFailed ? nullptr : child;
}
/**
* Returns whether the fork server was ever active. Thread-safe.
*/
static bool WasUsed() { return sForkServiceUsed; }
private:
// Called when a message is received.
void OnMessageReceived(UniquePtr<IPC::Message> message);
@ -81,6 +86,7 @@ class ForkServiceChild {
UniquePtr<MiniTransceiver> mTcver;
static UniquePtr<ForkServiceChild> sForkServiceChild;
static Atomic<bool> sForkServiceUsed;
pid_t mRecvPid;
bool mFailed; // The forkserver has crashed or disconnected.
GeckoChildProcessHost* mProcess;