blob: b6d8fa8a6886f199745c8153aea56c194a13da5c [file] [log] [blame]
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>
#include "src/core/lib/event_engine/forkable.h"
#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
#include <pthread.h>
#include "absl/container/flat_hash_set.h"
#include "src/core/lib/gprpp/no_destruct.h"
#include "src/core/lib/gprpp/sync.h"
namespace grpc_event_engine {
namespace experimental {
namespace {
grpc_core::NoDestruct<grpc_core::Mutex> g_mu;
bool g_registered ABSL_GUARDED_BY(g_mu){false};
// This must be ordered because there are ordering dependencies between
// certain fork handlers.
grpc_core::NoDestruct<std::vector<Forkable*>> g_forkables ABSL_GUARDED_BY(g_mu);
} // namespace
Forkable::Forkable() { ManageForkable(this); }
Forkable::~Forkable() { StopManagingForkable(this); }
void RegisterForkHandlers() {
grpc_core::MutexLock lock(g_mu.get());
if (!std::exchange(g_registered, true)) {
pthread_atfork(PrepareFork, PostforkParent, PostforkChild);
}
};
void PrepareFork() {
grpc_core::MutexLock lock(g_mu.get());
for (auto forkable_iter = g_forkables->rbegin();
forkable_iter != g_forkables->rend(); ++forkable_iter) {
(*forkable_iter)->PrepareFork();
}
}
void PostforkParent() {
grpc_core::MutexLock lock(g_mu.get());
for (auto* forkable : *g_forkables) {
forkable->PostforkParent();
}
}
void PostforkChild() {
grpc_core::MutexLock lock(g_mu.get());
for (auto* forkable : *g_forkables) {
forkable->PostforkChild();
}
}
void ManageForkable(Forkable* forkable) {
grpc_core::MutexLock lock(g_mu.get());
g_forkables->push_back(forkable);
}
void StopManagingForkable(Forkable* forkable) {
grpc_core::MutexLock lock(g_mu.get());
auto iter = std::find(g_forkables->begin(), g_forkables->end(), forkable);
GPR_ASSERT(iter != g_forkables->end());
g_forkables->erase(iter);
}
} // namespace experimental
} // namespace grpc_event_engine
#else // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
namespace grpc_event_engine {
namespace experimental {
Forkable::Forkable() {}
Forkable::~Forkable() {}
void RegisterForkHandlers() {}
void PrepareFork() {}
void PostforkParent() {}
void PostforkChild() {}
void ManageForkable(Forkable* /* forkable */) {}
void StopManagingForkable(Forkable* /* forkable */) {}
} // namespace experimental
} // namespace grpc_event_engine
#endif // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK