diff --git a/core/base/inc/TVirtualMutex.h b/core/base/inc/TVirtualMutex.h
index fb15648e7e1e78717a39beaea7d4376e2f172cba..4f21f7590e58c55c1e068b9357207fdb95a9328f 100644
--- a/core/base/inc/TVirtualMutex.h
+++ b/core/base/inc/TVirtualMutex.h
@@ -94,6 +94,53 @@ public:
    ClassDefNV(TLockGuard,0)  // Exception safe locking/unlocking of mutex
 };
 
+namespace ROOT {
+
+//////////////////////////////////////////////////////////////////////////
+//                                                                      //
+// TLockSuspend                                                         //
+//                                                                      //
+// This class provides mutex supension management in a guaranteed and   //
+// exception safe way. Use like this:                                   //
+// {                                                                    //
+//    TLockSuspend guard(mutex);                                        //
+//    ... // do something                                               //
+// }                                                                    //
+// when guard is created, 'suspend' the lock by calling Reset on the    //
+// on the mutex and when the guard goes out of scope the mutex is       //
+// restored in the TLockSuspend destructor.                             //
+// The exception mechanism takes care of calling the dtors              //
+// of local objects so it is exception safe.                            //
+//                                                                      //
+//////////////////////////////////////////////////////////////////////////
+
+class TLockSuspend {
+private:
+   TVirtualMutex *const fMutex;
+
+   std::unique_ptr<TVirtualMutex::State> fState;
+
+   TLockSuspend(const TLockSuspend &) = delete;
+   TLockSuspend &operator=(const TLockSuspend &) = delete;
+
+public:
+   TLockSuspend(TVirtualMutex *mutex) : fMutex(mutex)
+   {
+      if (fMutex)
+         fState = mutex->Reset();
+   }
+
+   ~TLockSuspend()
+   {
+      if (fMutex)
+         fMutex->Restore(std::move(fState));
+   }
+
+   ClassDefNV(TLockSuspend, 0) // Exception safe Reset/Restore of mutex
+};
+
+} // Namespace ROOT.
+
 // Zero overhead macros in case not compiled with thread support
 #if defined (_REENTRANT) || defined (WIN32)
 
@@ -108,11 +155,13 @@ public:
    R__LOCKGUARD(mutex)
 #define R__LOCKGUARD_NAMED(name,mutex) TLockGuard _NAME2_(R__guard,name)(mutex)
 #define R__LOCKGUARD_UNLOCK(name) _NAME2_(R__guard,name).UnLock()
+#define R__LOCK_SUSPEND(mutex) TLockSuspend _R__UNIQUE_(R__guard)(mutex)
 #else
 #define R__LOCKGUARD(mutex)  (void)mutex; { }
 #define R__LOCKGUARD_NAMED(name,mutex) (void)mutex; { }
 #define R__LOCKGUARD2(mutex) (void)mutex; { }
 #define R__LOCKGUARD_UNLOCK(name) { }
+#define R__LOCK_SUSPEND(mutex) { }
 #endif
 
 #ifdef R__USE_IMT
diff --git a/core/metacling/src/TClingCallFunc.cxx b/core/metacling/src/TClingCallFunc.cxx
index 6c944724fc86c982edf57c9051d86f6d13d4bd03..dd23548f313e3fa4c5ceb7131af6029d8f38682f 100644
--- a/core/metacling/src/TClingCallFunc.cxx
+++ b/core/metacling/src/TClingCallFunc.cxx
@@ -1791,15 +1791,17 @@ void TClingCallFunc::execWithULL(void *address, cling::Value *val)
 
 
 #define R__CF_InitRetAndExec(T, address, QT, ret)                 \
+{                                                                 \
    *ret = cling::Value::Create<T>(QT.getAsOpaquePtr(), *fInterp); \
    /* Release lock during user function execution*/               \
-   R__LOCKGUARD_UNLOCK(global);                                   \
+   R__LOCK_SUSPEND(gInterpreterMutex);                            \
                                                                   \
    static_assert(std::is_integral<T>::value, "Must be called with integral T"); \
    if (std::is_signed<T>::value)                                  \
-      execWithLL<T>(address, ret);                            \
+      execWithLL<T>(address, ret);                                \
    else                                                           \
-      execWithULL<T>(address, ret)
+      execWithULL<T>(address, ret);                               \
+}
 
 
 void TClingCallFunc::exec_with_valref_return(void *address, cling::Value *ret)
@@ -1820,14 +1822,14 @@ void TClingCallFunc::exec_with_valref_return(void *address, cling::Value *ret)
       QualType QT = Context.getLValueReferenceType(ClassTy);
       *ret = cling::Value(QT, *fInterp);
       // Store the new()'ed address in getPtr()
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       exec(address, &ret->getPtr());
       return;
    }
    QualType QT = FD->getReturnType().getCanonicalType();
    if (QT->isReferenceType()) {
       *ret = cling::Value(QT, *fInterp);
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       exec(address, &ret->getPtr());
       return;
    } else if (QT->isMemberPointerType()) {
@@ -1839,24 +1841,24 @@ void TClingCallFunc::exec_with_valref_return(void *address, cling::Value *ret)
          // But that's not relevant: we use it as a non-builtin, allocated
          // type.
          *ret = cling::Value(QT, *fInterp);
-         R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+         R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
          exec(address, ret->getPtr());
          return;
       }
       // We are a function member pointer.
       *ret = cling::Value(QT, *fInterp);
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       exec(address, &ret->getPtr());
       return;
    } else if (QT->isPointerType() || QT->isArrayType()) {
       // Note: ArrayType is an illegal function return value type.
       *ret = cling::Value::Create<void*>(QT.getAsOpaquePtr(), *fInterp);
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       exec(address, &ret->getPtr());
       return;
    } else if (QT->isRecordType()) {
       *ret = cling::Value(QT, *fInterp);
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       exec(address, ret->getPtr());
       return;
    } else if (const EnumType *ET = dyn_cast<EnumType>(&*QT)) {
@@ -1864,17 +1866,18 @@ void TClingCallFunc::exec_with_valref_return(void *address, cling::Value *ret)
       //       of the enum here.
       (void) ET;
       *ret = cling::Value(QT, *fInterp);
-      R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+      R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
       execWithLL<int>(address, ret);
       return;
    } else if (const BuiltinType *BT = dyn_cast<BuiltinType>(&*QT)) {
       switch (BT->getKind()) {
-         case BuiltinType::Void:
+         case BuiltinType::Void: {
             *ret = cling::Value::Create<void>(QT.getAsOpaquePtr(), *fInterp);
-            R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+            R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
             exec(address, 0);
             return;
             break;
+         }
 
             //
             //  Unsigned Types
@@ -1967,24 +1970,27 @@ void TClingCallFunc::exec_with_valref_return(void *address, cling::Value *ret)
                   "Invalid type 'Half'!");
             return;
             break;
-         case BuiltinType::Float:
+         case BuiltinType::Float: {
             *ret = cling::Value::Create<float>(QT.getAsOpaquePtr(), *fInterp);
-            R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+            R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
             exec(address, &ret->getFloat());
             return;
             break;
-         case BuiltinType::Double:
+         }
+         case BuiltinType::Double: {
             *ret = cling::Value::Create<double>(QT.getAsOpaquePtr(), *fInterp);
-            R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+            R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
             exec(address, &ret->getDouble());
             return;
             break;
-         case BuiltinType::LongDouble:
+         }
+         case BuiltinType::LongDouble: {
             *ret = cling::Value::Create<long double>(QT.getAsOpaquePtr(), *fInterp);
-            R__LOCKGUARD_UNLOCK(global); // Release lock during user function execution
+            R__LOCK_SUSPEND(gInterpreterMutex); // Release lock during user function execution
             exec(address, &ret->getLongDouble());
             return;
             break;
+         }
             //
             //  Language-Specific Types
             //