From 6568fb2fe4618fafef3555e90fce41f966a946f9 Mon Sep 17 00:00:00 2001
From: Axel Naumann <Axel.Naumann@cern.ch>
Date: Tue, 29 Aug 2017 22:00:43 +0200
Subject: [PATCH] Use new TMutex::Reset/Restore() to clear any and all locks
 active before entering user code.

This is kosher because the locks were taken to forbid other threads from modifying state while this thread is modifying state.
But this thread will not modify any state while the user code is active; thus while that user code is active,
the mutex can be completely reset, and restored once the user code returns.
---
 core/metacling/src/TCling.cxx          | 15 +++++++++------
 core/metacling/src/TClingCallbacks.cxx | 14 +++++++-------
 core/metacling/src/TClingCallbacks.h   |  2 +-
 3 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx
index c716ee1e3ec..387e492f8b2 100644
--- a/core/metacling/src/TCling.cxx
+++ b/core/metacling/src/TCling.cxx
@@ -354,20 +354,23 @@ void TCling__PrintStackTrace() {
 /// Lock the interpreter.
 
 extern "C"
-void TCling__LockInterpreterMutex() {
-   if (gInterpreterMutex) gInterpreterMutex->Lock();
+void TCling__RestoreInterpreterMutex(void* state) {
+   if (gInterpreterMutex && state) {
+      std::unique_ptr<TVirtualMutex::State> uniqueP{static_cast<TVirtualMutex::State*>(state)};
+      gInterpreterMutex->Restore(std::move(uniqueP));
+   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 /// Unlock the interpreter.
 
 extern "C"
-bool TCling__UnlockInterpreterMutex() {
+void* TCling__ResetInterpreterMutex() {
    if (gInterpreterMutex) {
-      gInterpreterMutex->UnLock();
-      return true;
+      auto uniqueP = gInterpreterMutex->Reset();
+      return uniqueP.release();
    }
-   return false;
+   return nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/core/metacling/src/TClingCallbacks.cxx b/core/metacling/src/TClingCallbacks.cxx
index 16689a8b1b5..3431facaecf 100644
--- a/core/metacling/src/TClingCallbacks.cxx
+++ b/core/metacling/src/TClingCallbacks.cxx
@@ -61,8 +61,8 @@ extern "C" {
    void TCling__LibraryUnloadedRTTI(const void* dyLibHandle,
                                     llvm::StringRef canonicalName);
    void TCling__PrintStackTrace();
-   void TCling__LockInterpreterMutex();
-   bool TCling__UnlockInterpreterMutex();
+   void TCling__RestoreInterpreterMutex(void* state);
+   void* TCling__ResetInterpreterMutex();
 }
 
 TClingCallbacks::TClingCallbacks(cling::Interpreter* interp)
@@ -788,12 +788,12 @@ void TClingCallbacks::PrintStackTrace() {
 
 void TClingCallbacks::EnteringUserCode() {
    // We can safely assume that if the lock exist already when we are in Cling code,
-   // then the lock has (or should been taken) already.  So it is fair to unlock it.
-   fMutexExistedWhenEnteringUserCode.push(TCling__UnlockInterpreterMutex());
+   // then the lock has (or should been taken) already. Any action (that caused callers
+   // to take the lock) is halted during ProcessLine. So it is fair to unlock it.
+   fMutexStatesWhenEnteringUserCode.push(TCling__ResetInterpreterMutex());
 }
 
 void TClingCallbacks::ReturnedFromUserCode() {
-   if (fMutexExistedWhenEnteringUserCode.top())
-      TCling__LockInterpreterMutex();
-   fMutexExistedWhenEnteringUserCode.pop();
+   TCling__RestoreInterpreterMutex(fMutexStatesWhenEnteringUserCode.top());
+   fMutexStatesWhenEnteringUserCode.pop();
 }
diff --git a/core/metacling/src/TClingCallbacks.h b/core/metacling/src/TClingCallbacks.h
index 16a7ecd7c39..1e54f5f1540 100644
--- a/core/metacling/src/TClingCallbacks.h
+++ b/core/metacling/src/TClingCallbacks.h
@@ -45,7 +45,7 @@ private:
    bool fIsAutoParsingSuspended;
    bool fPPOldFlag;
    bool fPPChanged;
-   std::stack<bool> fMutexExistedWhenEnteringUserCode;
+   std::stack<void*> fMutexStatesWhenEnteringUserCode;
 public:
    TClingCallbacks(cling::Interpreter* interp);
 
-- 
GitLab