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)
 {

Reply via email to