#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};
grpc_core::NoDestruct<std::vector<Forkable*>> g_forkables ABSL_GUARDED_BY(g_mu);
}
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);
}
}
}
#else
namespace grpc_event_engine {
namespace experimental {
Forkable::Forkable() { … }
Forkable::~Forkable() { … }
void RegisterForkHandlers() { … }
void PrepareFork() { … }
void PostforkParent() { … }
void PostforkChild() { … }
void ManageForkable(Forkable* ) { … }
void StopManagingForkable(Forkable* ) { … }
}
}
#endif