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 //