This is an automated email from the ASF dual-hosted git repository. wkaras pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new 50cec3b9b6 Eliminate function-scope thread_local in Regex.cc. (#10150) 50cec3b9b6 is described below commit 50cec3b9b6cc07a39442771f36f9cadae546d3aa Author: Walt Karas <wka...@yahooinc.com> AuthorDate: Mon Aug 7 14:01:53 2023 -0400 Eliminate function-scope thread_local in Regex.cc. (#10150) It appears to be the case that, in the C/C++ runtime for Linux, there is a mutex that is locked both: 1) When initializing non-local variables in a shared library, while it is being loaded by calling dlopen(), and 2) When execution encounters the definition of a thread_local variable within a function. It seems that the mutex is locked even if the variable has already been initialized, presumably to check whether it was initialized. This has been causing problems for the DbgCtl class. When an instance of DbgCtl is initialized, it locks a mutex (for the registry of instances). The instance initialization then (indirectly) calls a function (in Regex.cc) that defines a thread_local varaiable. The result is scenarios that sometimes lead to deadlock. For example: 1) dlopen() is called to load a plugin. The runtime's mutex is taken. 2) Another thread starts initializing a DbgCtl instance, and takes the instance registry mutex. 3) The non-local initialization of the shared library starts the intialization of another DbgCtl instance. This thread now blocks trying to lock the registry mutex. 4) The other thread now enters the function in Regex.cc that defines a thread_local object. It blocks on the runtime's mutex, which it needs to lock in order to do/check the thread_local instances. Deadlock. This PR fixes the problem, by eliminating the thread_local variable that's defined in a function. --- src/tscore/Regex.cc | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/tscore/Regex.cc b/src/tscore/Regex.cc index 22bb2e1c9e..dc03a9d778 100644 --- a/src/tscore/Regex.cc +++ b/src/tscore/Regex.cc @@ -29,22 +29,31 @@ #include "tscore/Regex.h" #ifdef PCRE_CONFIG_JIT -static pcre_jit_stack * -get_jit_stack(void *data ATS_UNUSED) +namespace { - thread_local struct JitStack { - JitStack() - { - jit_stack = pcre_jit_stack_alloc(ats_pagesize(), 1024 * 1024); // 1 page min and 1MB max - } - ~JitStack() { pcre_jit_stack_free(jit_stack); } +thread_local pcre_jit_stack *jit_stack; - pcre_jit_stack *jit_stack = nullptr; - } stack; +struct JitStackCleanup { + ~JitStackCleanup() + { + if (jit_stack) { + pcre_jit_stack_free(jit_stack); + } + } +}; +thread_local JitStackCleanup jsc; - return stack.jit_stack; +pcre_jit_stack * +get_jit_stack(void *) +{ + if (!jit_stack) { + jit_stack = pcre_jit_stack_alloc(ats_pagesize(), 1024 * 1024); // 1 page min and 1MB max + } + return jit_stack; } -#endif + +} // end anonymous namespace +#endif // def PCRE_CONFIG_JIT Regex::Regex(Regex &&that) noexcept : regex(that.regex), regex_extra(that.regex_extra) {