From c5213ceff9edc723cbf56a5f917083ff4a025bf0 Mon Sep 17 00:00:00 2001 From: Richard Belleville Date: Fri, 3 Mar 2023 16:08:06 -0800 Subject: [PATCH] [fork] Entirely opt EE threads out of ExecCtx counting (#32536) Follow-up to https://github.com/grpc/grpc/pull/32229. https://github.com/grpc/grpc/pull/32229 incremented the `ExecCtx` count unconditionally. It was previously impossible for a thread to exit `IncExecCtxCount` while `fork_complete_` was `false`. These same threads then went on to _decrement_ `count_` while the fork was still in progress, putting `count_` well below its expected range ([0, 1] while blocking and [2, inf) while not blocking). This resulted in cases where `count_` would be stuck at a negative number with a thread infinitely looping through `IncExecCtxCount`. This PR instead opts EE threads out of ExecCtx counting entirely. They handle clean-up of their threads separately through a separate set of handlers registered by an entirely separate invocation of `pthread_atfork`. This resolves the issue pointed out in [this comment](https://github.com/grpc/grpc/issues/31885#issuecomment-1426445192). --- src/core/lib/gprpp/fork.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/core/lib/gprpp/fork.cc b/src/core/lib/gprpp/fork.cc index e46676bf1d2..532f1551334 100644 --- a/src/core/lib/gprpp/fork.cc +++ b/src/core/lib/gprpp/fork.cc @@ -67,7 +67,6 @@ class ExecCtxState { // EventEngine is expected to terminate all threads before fork, and so this // extra work is unnecessary if (grpc_event_engine::experimental::ThreadLocal::IsEventEngineThread()) { - gpr_atm_no_barrier_fetch_add(&count_, 1); return; } gpr_atm count = gpr_atm_no_barrier_load(&count_); @@ -89,7 +88,12 @@ class ExecCtxState { } } - void DecExecCtxCount() { gpr_atm_no_barrier_fetch_add(&count_, -1); } + void DecExecCtxCount() { + if (grpc_event_engine::experimental::ThreadLocal::IsEventEngineThread()) { + return; + } + gpr_atm_no_barrier_fetch_add(&count_, -1); + } bool BlockExecCtx() { // Assumes there is an active ExecCtx when this function is called