diff --git a/cint/cintex/src/Cintex.cxx b/cint/cintex/src/Cintex.cxx index 92f59d20760fe..9b73af23b4648 100644 --- a/cint/cintex/src/Cintex.cxx +++ b/cint/cintex/src/Cintex.cxx @@ -25,6 +25,8 @@ #include #include "TROOT.h" +#include "TInterpreter.h" //gCINTMutex +#include "TVirtualMutex.h" using namespace ROOT::Reflex; using namespace ROOT::Cintex; @@ -187,6 +189,7 @@ namespace ROOT { } void Callback::operator () ( const Type& t ) { + R__LOCKGUARD2(gCINTMutex); ArtificialSourceFile asf; int autoload = G__set_class_autoloading(0); // To avoid recursive loads if ( t.IsClass() || t.IsStruct() ) { @@ -205,6 +208,7 @@ namespace ROOT { } void Callback::operator () ( const Member& m ) { + R__LOCKGUARD2(gCINTMutex); ArtificialSourceFile asf; int autoload = G__set_class_autoloading(0); // To avoid recursive loads if ( m.IsFunctionMember() ) { diff --git a/cint/cintex/src/ROOTClassEnhancer.cxx b/cint/cintex/src/ROOTClassEnhancer.cxx index 9c123639c06df..66d46ff0a2e66 100644 --- a/cint/cintex/src/ROOTClassEnhancer.cxx +++ b/cint/cintex/src/ROOTClassEnhancer.cxx @@ -21,6 +21,7 @@ #include "TClassStreamer.h" #include "TCollectionProxyInfo.h" #include "TVirtualCollectionProxy.h" +#include "TVirtualMutex.h" #include "TMemberInspector.h" #include "RVersion.h" #include "Reflex/Reflex.h" @@ -35,6 +36,9 @@ #include #include #include +#if __cplusplus > 199711L +#include +#endif #if ROOT_VERSION_CODE >= ROOT_VERSION(5,1,1) #include "TVirtualIsAProxy.h" @@ -44,6 +48,8 @@ using namespace ROOT::Reflex; using namespace ROOT::Cintex; using namespace std; +static TVirtualMutex* gCintexMutex = 0; + namespace ROOT { namespace Cintex { class IsAProxy; @@ -52,7 +58,11 @@ namespace ROOT { namespace Cintex { Type fType; string fName; +#if __cplusplus > 199711L + std::atomic fTclass; +#else TClass* fTclass; +#endif TClass* fLastClass; std::map fSub_types; const std::type_info* fLastType; @@ -174,7 +184,10 @@ namespace ROOT { namespace Cintex { // Constructor. fType = CleanType(t); fName = CintName(fType); - rootEnhancerInfos().push_back(this); + { + R__LOCKGUARD2(gCintexMutex); + rootEnhancerInfos().push_back(this); + } fMyType = &t.TypeInfo(); fIsVirtual = TypeGet().IsVirtual(); fClassInfo = 0; @@ -361,37 +374,46 @@ namespace ROOT { namespace Cintex { if ( ! obj || ! fIsVirtual ) { return Tclass(); } - else { - // Avoid the case that the first word is a virtual_base_offset_table instead of - // a virtual_function_table - long Offset = **(long**)obj; - if ( Offset == 0 ) return Tclass(); - DynamicStruct_t* p = (DynamicStruct_t*)obj; - const std::type_info& typ = typeid(*p); + // Avoid the case that the first word is a virtual_base_offset_table instead of + // a virtual_function_table + long Offset = **(long**)obj; + if ( Offset == 0 ) return Tclass(); - if ( &typ == fMyType ) { - return Tclass(); - } - else if ( &typ == fLastType ) { + DynamicStruct_t* p = (DynamicStruct_t*)obj; + const std::type_info& typ = typeid(*p); + + if ( &typ == fMyType ) { + return Tclass(); + } + { + R__LOCKGUARD2(gCintexMutex); + if ( &typ == fLastType ) { return fLastClass; } + // Check if TypeNth is already in sub-class cache - else if ( 0 != (fLastClass=fSub_types[&typ]) ) { + TClass* findClass = fSub_types[&typ]; + if ( 0 != findClass ) { + fLastClass = findClass; fLastType = &typ; + return fLastClass; } - // Last resort: lookup root class - else { - std::string nam; - Type t = Type::ByTypeInfo(typ); - if (t) nam = CintName(t); - else nam = CintName(Tools::Demangle(typ)); - fLastClass = ROOT::GetROOT()->GetClass(nam.c_str()); - fSub_types[fLastType=&typ] = fLastClass; - } + } + // Last resort: lookup root class + TClass* returnValue; + std::string nam; + Type t = Type::ByTypeInfo(typ); + if (t) nam = CintName(t); + else nam = CintName(Tools::Demangle(typ)); + returnValue = ROOT::GetROOT()->GetClass(nam.c_str()); + { + R__LOCKGUARD2(gCintexMutex); + fLastClass = returnValue; + fSub_types[fLastType=&typ] = fLastClass; } //std::cout << "Cintex: IsA:" << TypeNth.Name(SCOPED) << " dynamic:" << dtype.Name(SCOPED) << std::endl; - return fLastClass; + return returnValue; } TClass* ROOTClassEnhancerInfo::Default_CreateClass( Type typ, ROOT::TGenericClassInfo* info) { diff --git a/cint/reflex/python/genreflex/gendict.py b/cint/reflex/python/genreflex/gendict.py index f64ce1f15b8b6..69e58bd745a9b 100644 --- a/cint/reflex/python/genreflex/gendict.py +++ b/cint/reflex/python/genreflex/gendict.py @@ -2654,6 +2654,8 @@ def ClassDefImplementation(selclasses, self) : returnValue += '#endif\n' returnValue += '#include "TClass.h"\n' returnValue += '#include "TMemberInspector.h"\n' + returnValue += '#include "TInterpreter.h"\n' + returnValue += '#include "TVirtualMutex.h"\n' returnValue += '#include "RtypesImp.h"\n' # for GenericShowMembers etc returnValue += '#include "TIsAProxy.h"\n' haveClassDef = 0 @@ -2725,8 +2727,11 @@ def ClassDefImplementation(selclasses, self) : specclname = clname returnValue += template + 'TClass* ' + specclname + '::Class() {\n' - returnValue += ' if (!fgIsA)\n' - returnValue += ' fgIsA = TClass::GetClass("' + clname[2:] + '");\n' + returnValue += ' if (!fgIsA) {\n' + returnValue += ' R__LOCKGUARD2(gCINTMutex);' + returnValue += ' if (!fgIsA)\n' + returnValue += ' fgIsA = TClass::GetClass("' + clname[2:] + '");\n' + returnValue += ' }\n' returnValue += ' return fgIsA;\n' returnValue += '}\n' returnValue += template + 'const char * ' + specclname + '::Class_Name() {return "' + clname[2:] + '";}\n' @@ -2814,7 +2819,11 @@ def ClassDefImplementation(selclasses, self) : returnValue += ' b.WriteClassBuffer(' + clname + '::Class(),this);\n' returnValue += ' }\n' returnValue += '}\n' - returnValue += template + 'TClass* ' + specclname + '::fgIsA = 0;\n' + #must strip of leading '::' to avoid ambiguity with embedded type in atomic_TClass_ptr + if len(specclname) > 2: + if specclname[:2] == '::': + specclname = specclname[2:] + returnValue += template + 'atomic_TClass_ptr ' + specclname + '::fgIsA(0);\n' returnValue += namespacelevel * '}' + '\n' elif derivesFromTObject : # no fgIsA etc members but derives from TObject! diff --git a/config/Makefile.linux b/config/Makefile.linux index 432b4d653420a..022c9fff0ac22 100644 --- a/config/Makefile.linux +++ b/config/Makefile.linux @@ -36,7 +36,7 @@ COMPILER = gnu # Linker: LD = g++ -LDFLAGS = -m32 $(OPT) $(EXTRA_LDFLAGS) -Wl,--no-undefined -Wl,--as-needed +LDFLAGS = -m32 -Wl,--hash-style=gnu $(OPT) $(EXTRA_LDFLAGS) SOFLAGS = -shared -Wl,-soname, SOEXT = so diff --git a/config/Makefile.linuxarm b/config/Makefile.linuxarm index 55862207300f1..a6520d2e7a124 100644 --- a/config/Makefile.linuxarm +++ b/config/Makefile.linuxarm @@ -14,13 +14,16 @@ else OPT = $(OPTFLAGS) NOOPT = endif +ifeq ($(CXX11),yes) +CXX11FLAGS = -std=c++11 -Wno-deprecated-declarations +endif # Compiler: CXX = g++ CC = gcc -CXXFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CXXFLAGS) +CXXFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CXXFLAGS) $(CXX11FLAGS) CFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CFLAGS) -CINTCXXFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CXXFLAGS) \ +CINTCXXFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CXXFLAGS) $(CXX11FLAGS) \ -DG__REGEXP -DG__UNIX -DG__SHAREDLIB \ -DG__OSFDLL -DG__ROOT -DG__REDIRECTIO CINTCFLAGS = -Wall -fsigned-char -fPIC $(EXTRA_CFLAGS) \ diff --git a/config/Makefile.linuxx8664gcc b/config/Makefile.linuxx8664gcc index 3259717db5cc5..551bb942b5e39 100644 --- a/config/Makefile.linuxx8664gcc +++ b/config/Makefile.linuxx8664gcc @@ -39,7 +39,7 @@ COMPILER = gnu # Linker: LD = g++ -LDFLAGS = -m64 $(OPT) $(EXTRA_LDFLAGS) -Wl,--no-undefined -Wl,--as-needed +LDFLAGS = -m64 -Wl,--hash-style=gnu $(OPT) $(EXTRA_LDFLAGS) SOFLAGS = -shared -Wl,-soname, SOEXT = so diff --git a/configure b/configure index 6614424544fcc..7ceb02cdf62d5 100755 --- a/configure +++ b/configure @@ -380,14 +380,14 @@ check_libcompat() { case $arch in macosx) - logmsg " lipo -info $chklibcompat | grep ' i386'" - if lipo -info $chklibcompat | grep ' i386' > /dev/null 2>& 1 ; then + logmsg " otool -fhv $chklibcompat | grep -i ' i386'" + if otool -fhv $chklibcompat | grep -i ' i386' > /dev/null 2>& 1 ; then ret=1 fi ;; macosx64) - logmsg " lipo -info $chklibcompat | grep ' x86_64'" - if lipo -info $chklibcompat | grep ' x86_64' > /dev/null 2>& 1 ; then + logmsg " otool -fhv $chklibcompat | grep -i ' x86_64'" + if otool -fhv $chklibcompat | grep -i ' x86_64' > /dev/null 2>& 1 ; then ret=1 fi ;; @@ -2851,7 +2851,7 @@ result "$enable_builtin_pcre" # if test "x$enable_builtin_zlib" = "xno" ; then check_header "zlib.h" "" \ - $ZLIB ${ZLIB:+$ZLIB/include} \ + $ZLIB_ROOT/include $ZLIB ${ZLIB:+$ZLIB/include} \ ${finkdir:+$finkdir/include} \ /usr/local/include /usr/include/zlib /usr/local/include/zlib \ /opt/zlib/include /usr/include @@ -2863,7 +2863,7 @@ if test "x$enable_builtin_zlib" = "xno" ; then fi check_library "libz" "$enable_shared" "" \ - $ZLIB ${ZLIB:+$ZLIB/lib} \ + $ZLIB_ROOT/lib $ZLIB ${ZLIB:+$ZLIB/lib} \ /usr/local/zlib/lib /usr/local/lib \ /usr/lib/zlib /usr/local/lib/zlib /usr/zlib/lib /usr/lib \ /usr/zlib /usr/local/zlib /opt/zlib /opt/zlib/lib @@ -4398,12 +4398,12 @@ if test ! "x$enable_asimage" = "xno" ; then # for a system library, then see if we have various headers needed. if test "x$enable_builtin_afterimage" = "xyes" && test ! "x$enable_cocoa" = "xyes"; then check_header "jpeglib.h" "" \ - $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ + $LIBJPG_ROOT/include $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ ${finkdir:+$finkdir/include} \ /usr/local/include /usr/include /opt/include asjpegincdir=$found_dir check_header "png.h" "" \ - $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ + $LIBPNG_ROOT/include $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ ${ASPNG:+$ASPNG/include} \ ${finkdir:+$finkdir/include} \ /usr/local/include /usr/X11/include /usr/include \ @@ -4411,7 +4411,7 @@ if test ! "x$enable_asimage" = "xno" ; then aspngincdir=$found_dir if test ! "x$enable_astiff" = "xno" ; then check_header "tiffio.h" "" \ - $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ + $LIBTIFF_ROOT/include $ASIMAGE ${ASIMAGE:+$ASIMAGE/include} \ ${finkdir:+$finkdir/include} \ /usr/local/include /usr/include /opt/include astiffincdir=$found_dir @@ -4427,11 +4427,14 @@ if test ! "x$enable_asimage" = "xno" ; then # add libpng which needs libz if test ! "x$enable_astiff" = "xno" ; then aslibs="libjpeg libtiff libz libpng" + extra_libtiff_path=$LIBTIFF_ROOT/lib else aslibs="libjpeg libz libpng" + extra_libtiff_path= fi for k in $aslibs ; do check_library $k "$enable_shared" "" \ + $extra_libtiff_path $LIBJPG_ROOT/lib $LIBPNG_ROOT/lib $ZLIB_ROOT/lib \ $ASIMAGE ${ASIMAGE:+$ASIMAGE/lib} ${ASPNG:+$ASPNG/lib} \ ${finkdir:+$finkdir/lib} \ /usr/local/lib /usr/X11/lib /usr/lib /opt/lib diff --git a/core/base/inc/Rtypes.h b/core/base/inc/Rtypes.h index 345e82a30f1ee..7acc10bea8c1a 100644 --- a/core/base/inc/Rtypes.h +++ b/core/base/inc/Rtypes.h @@ -34,7 +34,9 @@ #include #include // part of stdio.h on systems that have it #include // part of string.h on systems that have it - +#if __cplusplus > 199711L +#include +#endif //---- forward declared class types -------------------------------------------- @@ -268,12 +270,17 @@ namespace ROOT { #include "TGenericClassInfo.h" #endif +#if __cplusplus > 199711L +typedef std::atomic atomic_TClass_ptr; +#else +typedef TClass* atomic_TClass_ptr; +#endif // Common part of ClassDef definition. // DeclFileLine() is not part of it since CINT uses that as trigger for // the class comment string. #define _ClassDef_(name,id) \ private: \ - static TClass *fgIsA; \ + static atomic_TClass_ptr fgIsA; \ public: \ static TClass *Class(); \ static const char *Class_Name(); \ @@ -290,7 +297,7 @@ public: \ // Version without any virtual functions. #define _ClassDefNV_(name,id) \ private: \ -static TClass *fgIsA; \ +static atomic_TClass_ptr fgIsA; \ public: \ static TClass *Class(); \ static const char *Class_Name(); \ diff --git a/core/base/inc/TROOT.h b/core/base/inc/TROOT.h index 78d3a96a07ac7..45ae6eafd9c2b 100644 --- a/core/base/inc/TROOT.h +++ b/core/base/inc/TROOT.h @@ -241,7 +241,7 @@ friend class TCintWithCling; Long_t ProcessLine(const char *line, Int_t *error = 0); Long_t ProcessLineSync(const char *line, Int_t *error = 0); Long_t ProcessLineFast(const char *line, Int_t *error = 0); - Bool_t ReadingObject() const { /* Deprecated (will be removed in next release) */ return fReadingObject; } + Bool_t ReadingObject() const; void RefreshBrowsers(); void RemoveClass(TClass *); void Reset(Option_t *option=""); @@ -258,7 +258,7 @@ friend class TCintWithCling; void SetEscape(Bool_t flag = kTRUE) { fEscape = flag; } void SetLineIsProcessing() { fLineIsProcessing++; } void SetLineHasBeenProcessed() { if (fLineIsProcessing) fLineIsProcessing--; } - void SetReadingObject(Bool_t flag = kTRUE) { fReadingObject = flag; } + void SetReadingObject(Bool_t flag = kTRUE); void SetMustClean(Bool_t flag = kTRUE) { fMustClean=flag; } void SetSelectedPrimitive(const TObject *obj) { fPrimitive = obj; } void SetSelectedPad(TVirtualPad *pad) { fSelectPad = pad; } diff --git a/core/base/inc/TStorage.h b/core/base/inc/TStorage.h index d11177771b8b1..afef2e6e4c507 100644 --- a/core/base/inc/TStorage.h +++ b/core/base/inc/TStorage.h @@ -34,14 +34,14 @@ typedef char *(*ReAllocCharFun_t)(char*, size_t, size_t); class TStorage { private: - static ULong_t fgHeapBegin; // begin address of heap - static ULong_t fgHeapEnd; // end address of heap static size_t fgMaxBlockSize; // largest block allocated static FreeHookFun_t fgFreeHook; // function called on free static void *fgFreeHookData; // data used by this function static ReAllocFun_t fgReAllocHook; // custom ReAlloc static ReAllocCFun_t fgReAllocCHook; // custom ReAlloc with length check static Bool_t fgHasCustomNewDelete; // true if using ROOT's new/delete + static const UInt_t kObjectAllocMemValue = 0x99999999; + // magic number for ObjectAlloc public: virtual ~TStorage() { } @@ -77,16 +77,13 @@ class TStorage { static void AddToHeap(ULong_t begin, ULong_t end); static Bool_t IsOnHeap(void *p); + static Bool_t FilledByObjectAlloc(UInt_t* member); + ClassDef(TStorage,0) //Storage manager class }; #ifndef WIN32 -inline void TStorage::AddToHeap(ULong_t begin, ULong_t end) - { if (begin < fgHeapBegin) fgHeapBegin = begin; - if (end > fgHeapEnd) fgHeapEnd = end; } - -inline Bool_t TStorage::IsOnHeap(void *p) - { return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd; } +inline Bool_t TStorage::FilledByObjectAlloc(UInt_t *member) { return *member == kObjectAllocMemValue; } inline size_t TStorage::GetMaxBlockSize() { return fgMaxBlockSize; } diff --git a/core/base/inc/TSystem.h b/core/base/inc/TSystem.h index 0d1687c1d2e5e..fe39050428227 100644 --- a/core/base/inc/TSystem.h +++ b/core/base/inc/TSystem.h @@ -316,6 +316,10 @@ class TSystem : public TNamed { TSeqCollection *fCompiled; //List of shared libs from compiled macros to be deleted TSeqCollection *fHelpers; //List of helper classes for alternative file/directory access +#if __cplusplus > 199711L + static thread_local TString fgLastErrorString; //Last system error message +#endif + TSystem *FindHelper(const char *path, void *dirptr = 0); virtual Bool_t ConsistentWith(const char *path, void *dirptr = 0); virtual const char *ExpandFileName(const char *fname); @@ -340,7 +344,11 @@ class TSystem : public TNamed { virtual void SetProgname(const char *name); virtual void SetDisplay(); void SetErrorStr(const char *errstr); +#if __cplusplus > 199711L + const char *GetErrorStr() const { return fgLastErrorString; } +#else const char *GetErrorStr() const { return fLastErrorString; } +#endif virtual const char *GetError(); void RemoveOnExit(TObject *obj); virtual const char *HostName(); diff --git a/core/base/src/TError.cxx b/core/base/src/TError.cxx index f78e1d48a8515..ba374430c8be9 100644 --- a/core/base/src/TError.cxx +++ b/core/base/src/TError.cxx @@ -62,10 +62,8 @@ static void DebugPrint(const char *fmt, ...) { // Print debugging message to stderr and, on Windows, to the system debugger. - static Int_t buf_size = 2048; - static char *buf = 0; - - R__LOCKGUARD2(gErrorMutex); + static thread_local Int_t buf_size = 2048; + static thread_local char *buf = 0; va_list ap; va_start(ap, fmt); @@ -90,6 +88,8 @@ static void DebugPrint(const char *fmt, ...) } va_end(ap); + R__LOCKGUARD2(gErrorMutex); + fprintf(stderr, "%s", buf); #ifdef WIN32 @@ -197,10 +197,9 @@ void ErrorHandler(Int_t level, const char *location, const char *fmt, va_list ap { // General error handler function. It calls the user set error handler. - R__LOCKGUARD2(gErrorMutex); - static Int_t buf_size = 2048; - static char *buf = 0; + static thread_local Int_t buf_size = 2048; + static thread_local char *buf = 0; int vc = 0; va_list sap; @@ -233,9 +232,10 @@ void ErrorHandler(Int_t level, const char *location, const char *fmt, va_list ap va_end(ap); char *bp; - if (level >= kSysError && level < kFatal) + if (level >= kSysError && level < kFatal) { + R__LOCKGUARD2(gErrorMutex); bp = Form("%s (%s)", buf, gSystem->GetError()); - else + } else bp = buf; if (level != kFatal) diff --git a/core/base/src/TObject.cxx b/core/base/src/TObject.cxx index daa4514285f3b..45a4c5835518c 100644 --- a/core/base/src/TObject.cxx +++ b/core/base/src/TObject.cxx @@ -62,7 +62,7 @@ Bool_t TObject::fgObjectStat = kTRUE; ClassImp(TObject) //______________________________________________________________________________ -TObject::TObject() : fUniqueID(0), fBits(kNotDeleted) +TObject::TObject() : fBits(kNotDeleted) //Need to leave FUniqueID unset { // TObject constructor. It sets the two data words of TObject to their // initial values. The unique ID is set to 0 and the status word is @@ -71,8 +71,10 @@ TObject::TObject() : fUniqueID(0), fBits(kNotDeleted) // (see TEnv) the object is added to the global TObjectTable for // bookkeeping. - if (TStorage::IsOnHeap(this)) + if (TStorage::FilledByObjectAlloc(&fUniqueID)) fBits |= kIsOnHeap; + + fUniqueID = 0; if (fgObjectStat) TObjectTable::AddObj(this); } @@ -82,10 +84,9 @@ TObject::TObject(const TObject &obj) { // TObject copy ctor. - fUniqueID = obj.fUniqueID; // when really unique don't copy - fBits = obj.fBits; + fBits = obj.fBits; - if (TStorage::IsOnHeap(this)) + if (TStorage::FilledByObjectAlloc(&fUniqueID)) fBits |= kIsOnHeap; else fBits &= ~kIsOnHeap; @@ -93,6 +94,9 @@ TObject::TObject(const TObject &obj) fBits &= ~kIsReferenced; fBits &= ~kCanDelete; + //Set only after used in above call + fUniqueID = obj.fUniqueID; // when really unique don't copy + if (fgObjectStat) TObjectTable::AddObj(this); } diff --git a/core/base/src/TPluginManager.cxx b/core/base/src/TPluginManager.cxx index 8ff58da8a6c6d..a549fdb71e6b6 100644 --- a/core/base/src/TPluginManager.cxx +++ b/core/base/src/TPluginManager.cxx @@ -103,6 +103,8 @@ TPluginManager *gPluginMgr; // main plugin manager created in TROOT +static TVirtualMutex *gPluginManagerMutex; +static thread_local bool fgReadingDirs = false; ClassImp(TPluginHandler) @@ -470,67 +472,72 @@ void TPluginManager::LoadHandlersFromPluginDirs(const char *base) // dependency, check on some OS or ROOT capability or downloading // of the plugin. - if (!fBasesLoaded) { - fBasesLoaded = new THashTable(); - fBasesLoaded->SetOwner(); + //The destructor of TObjArray takes the gROOTMutex lock so we want to + // delete the object after release the gCINTMutex lock + TObjArray *dirs = nullptr; + { + R__LOCKGUARD2(gCINTMutex); + if (!fBasesLoaded) { + fBasesLoaded = new THashTable(); + fBasesLoaded->SetOwner(); - // make sure we have gPluginMgr availble in the plugin macros - gInterpreter->InitializeDictionaries(); - } - TString sbase = base; - if (sbase != "") { - sbase.ReplaceAll("::", "@@"); - if (fBasesLoaded->FindObject(sbase)) - return; - fBasesLoaded->Add(new TObjString(sbase)); - } + // make sure we have gPluginMgr availble in the plugin macros + gInterpreter->InitializeDictionaries(); + } + TString sbase = base; + if (sbase != "") { + sbase.ReplaceAll("::", "@@"); + if (fBasesLoaded->FindObject(sbase)) + return; + fBasesLoaded->Add(new TObjString(sbase)); + } - fReadingDirs = kTRUE; + fgReadingDirs = kTRUE; - TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)0); + TString plugindirs = gEnv->GetValue("Root.PluginPath", (char*)0); #ifdef WIN32 - TObjArray *dirs = plugindirs.Tokenize(";"); + dirs = plugindirs.Tokenize(";"); #else - TObjArray *dirs = plugindirs.Tokenize(":"); + dirs = plugindirs.Tokenize(":"); #endif - TString d; - for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) { - d = ((TObjString*)dirs->At(i))->GetString(); - // check if directory already scanned - Int_t skip = 0; - for (Int_t j = 0; j < i; j++) { - TString pd = ((TObjString*)dirs->At(j))->GetString(); - if (pd == d) { - skip++; - break; - } - } - if (!skip) { - if (sbase != "") { - const char *p = gSystem->ConcatFileName(d, sbase); - LoadHandlerMacros(p); - delete [] p; - } else { - void *dirp = gSystem->OpenDirectory(d); - if (dirp) { - if (gDebug > 0) - Info("LoadHandlersFromPluginDirs", "%s", d.Data()); - const char *f1; - while ((f1 = gSystem->GetDirEntry(dirp))) { - TString f = f1; - const char *p = gSystem->ConcatFileName(d, f); - LoadHandlerMacros(p); - fBasesLoaded->Add(new TObjString(f)); - delete [] p; - } - } - gSystem->FreeDirectory(dirp); - } + TString d; + for (Int_t i = 0; i < dirs->GetEntriesFast(); i++) { + d = ((TObjString*)dirs->At(i))->GetString(); + // check if directory already scanned + Int_t skip = 0; + for (Int_t j = 0; j < i; j++) { + TString pd = ((TObjString*)dirs->At(j))->GetString(); + if (pd == d) { + skip++; + break; + } + } + if (!skip) { + if (sbase != "") { + const char *p = gSystem->ConcatFileName(d, sbase); + LoadHandlerMacros(p); + delete [] p; + } else { + void *dirp = gSystem->OpenDirectory(d); + if (dirp) { + if (gDebug > 0) + Info("LoadHandlersFromPluginDirs", "%s", d.Data()); + const char *f1; + while ((f1 = gSystem->GetDirEntry(dirp))) { + TString f = f1; + const char *p = gSystem->ConcatFileName(d, f); + LoadHandlerMacros(p); + fBasesLoaded->Add(new TObjString(f)); + delete [] p; + } + } + gSystem->FreeDirectory(dirp); + } + } } + fgReadingDirs = kFALSE; } - delete dirs; - fReadingDirs = kFALSE; } //______________________________________________________________________________ @@ -541,20 +548,25 @@ void TPluginManager::AddHandler(const char *base, const char *regexp, // Add plugin handler to the list of handlers. If there is already a // handler defined for the same base and regexp it will be replaced. - if (!fHandlers) { - fHandlers = new TList; - fHandlers->SetOwner(); + { + R__LOCKGUARD2(gPluginManagerMutex); + if (!fHandlers) { + fHandlers = new TList; + fHandlers->SetOwner(); + } } - // make sure there is no previous handler for the same case RemoveHandler(base, regexp); - if (fReadingDirs) + if (fgReadingDirs) origin = gInterpreter->GetCurrentMacroName(); TPluginHandler *h = new TPluginHandler(base, regexp, className, pluginName, ctor, origin); - fHandlers->Add(h); + { + R__LOCKGUARD2(gPluginManagerMutex); + fHandlers->Add(h); + } } //______________________________________________________________________________ @@ -562,7 +574,7 @@ void TPluginManager::RemoveHandler(const char *base, const char *regexp) { // Remove handler for the specified base class and the specified // regexp. If regexp=0 remove all handlers for the specified base. - + R__LOCKGUARD2(gPluginManagerMutex); if (!fHandlers) return; TIter next(fHandlers); @@ -570,10 +582,10 @@ void TPluginManager::RemoveHandler(const char *base, const char *regexp) while ((h = (TPluginHandler*) next())) { if (h->fBase == base) { - if (!regexp || h->fRegexp == regexp) { - fHandlers->Remove(h); - delete h; - } + if (!regexp || h->fRegexp == regexp) { + fHandlers->Remove(h); + delete h; + } } } } @@ -587,6 +599,7 @@ TPluginHandler *TPluginManager::FindHandler(const char *base, const char *uri) LoadHandlersFromPluginDirs(base); + R__LOCKGUARD2(gPluginManagerMutex); TIter next(fHandlers); TPluginHandler *h; diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx index a3135619033c7..5ddb953c79b74 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -1817,6 +1817,28 @@ void TROOT::ReadGitInfo() delete [] filename; } +static thread_local Bool_t fgReadingObject = false; +//______________________________________________________________________________ +Bool_t TROOT::ReadingObject() const +{ + /* Deprecated (will be removed in next release) */ +#if __cplusplus > 199711L + return fgReadingObject; +#else + return fReadingObject; +#endif +} + +void TROOT::SetReadingObject(Bool_t flag) +{ +#if __cplusplus > 199711L + fgReadingObject = flag; +#else + fReadingObject = flag; +#endif +} + + //______________________________________________________________________________ const char *TROOT::GetGitDate() { diff --git a/core/base/src/TStorage.cxx b/core/base/src/TStorage.cxx index 4ea50e5179773..5207b49d7ff3b 100644 --- a/core/base/src/TStorage.cxx +++ b/core/base/src/TStorage.cxx @@ -62,8 +62,6 @@ #define PVOID (-1) -ULong_t TStorage::fgHeapBegin = (ULong_t)-1L; -ULong_t TStorage::fgHeapEnd; size_t TStorage::fgMaxBlockSize; FreeHookFun_t TStorage::fgFreeHook; void *TStorage::fgFreeHookData; @@ -323,15 +321,12 @@ void *TStorage::ObjectAlloc(size_t sz) { // Used to allocate a TObject on the heap (via TObject::operator new()). // Directly after this routine one can call (in the TObject ctor) - // TStorage::IsOnHeap() to find out if the just created object is on + // TStorage::FilledByObjectAlloc() to find out if the just created object is on // the heap. - // Needs to be protected by global mutex - R__LOCKGUARD(gGlobalMutex); - - ULong_t space = (ULong_t) ::operator new(sz); - AddToHeap(space, space+sz); - return (void*) space; + void* space = ::operator new(sz); + memset(space, kObjectAllocMemValue, sz); + return space; } //______________________________________________________________________________ @@ -349,9 +344,6 @@ void TStorage::ObjectDealloc(void *vp) { // Used to deallocate a TObject on the heap (via TObject::operator delete()). - // Needs to be protected by global mutex - R__LOCKGUARD(gGlobalMutex); - #ifndef NOCINT // to handle delete with placement called via CINT Long_t gvp = 0; @@ -450,15 +442,17 @@ void TStorage::EnableStatistics(int size, int ix) //______________________________________________________________________________ ULong_t TStorage::GetHeapBegin() { + ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00"); //return begin of heap - return fgHeapBegin; + return 0; } //______________________________________________________________________________ ULong_t TStorage::GetHeapEnd() { + ::Obsolete("GetHeapBegin()", "v5-34-00", "v6-02-00"); //return end of heap - return fgHeapEnd; + return 0; } //______________________________________________________________________________ @@ -482,21 +476,28 @@ void TStorage::SetCustomNewDelete() fgHasCustomNewDelete = kTRUE; } -#ifdef WIN32 //______________________________________________________________________________ -void TStorage::AddToHeap(ULong_t begin, ULong_t end) +void TStorage::AddToHeap(ULong_t, ULong_t) { //add a range to the heap - if (begin < fgHeapBegin) fgHeapBegin = begin; - if (end > fgHeapEnd) fgHeapEnd = end; + ::Obsolete("AddToHeap(ULong_t,ULong_t)", "v5-34-00", "v6-02-00"); } //______________________________________________________________________________ -Bool_t TStorage::IsOnHeap(void *p) +Bool_t TStorage::IsOnHeap(void *) { //is object at p in the heap? - return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd; + ::Obsolete("IsOnHeap(void*)", "v5-34-00", "v6-02-00"); + return false; +} + +#ifdef WIN32 +//______________________________________________________________________________ +Bool_t TStorage::FilledByObjectAlloc(UInt_t *member) +{ + //called by TObject's constructor to determine if object was created by call to new + return *member == kObjectAllocMemValue; } //______________________________________________________________________________ diff --git a/core/base/src/TString.cxx b/core/base/src/TString.cxx index b6500b95c0978..b53843f10b5b7 100644 --- a/core/base/src/TString.cxx +++ b/core/base/src/TString.cxx @@ -2348,20 +2348,32 @@ static const int cb_size = 4096; static const int fld_size = 2048; // a circular formating buffer +#if __cplusplus > 199711L +static thread_local char gFormbuf[cb_size]; // some slob for form overflow +static thread_local char *gBfree = gFormbuf; +static thread_local char *gEndbuf = &gFormbuf[cb_size-1]; +#else static char gFormbuf[cb_size]; // some slob for form overflow static char *gBfree = gFormbuf; static char *gEndbuf = &gFormbuf[cb_size-1]; - +#endif //______________________________________________________________________________ static char *SlowFormat(const char *format, va_list ap, int hint) { // Format a string in a formatting buffer (using a printf style // format descriptor). +#if __cplusplus > 199711L + static thread_local char *slowBuffer = 0; + static thread_local int slowBufferSize = 0; +#else static char *slowBuffer = 0; static int slowBufferSize = 0; + //NOTE: since slowBuffer is returned from this function, + // this lock guard is ineffectual in protecting slowBuffer reads R__LOCKGUARD2(gStringMutex); +#endif if (hint == -1) hint = fld_size; if (hint > slowBufferSize) { @@ -2407,8 +2419,12 @@ static char *Format(const char *format, va_list ap) // Format a string in a circular formatting buffer (using a printf style // format descriptor). +#if __cplusplus <= 199711L + //NOTE: since an address into the shared buffer is returned from this + // function, this lock is ineffectual in protecting reads from + // the buffer. R__LOCKGUARD2(gStringMutex); - +#endif char *buf = gBfree; if (buf+fld_size > gEndbuf) diff --git a/core/base/src/TSystem.cxx b/core/base/src/TSystem.cxx index f517c25d5b993..9df61fa4528c6 100644 --- a/core/base/src/TSystem.cxx +++ b/core/base/src/TSystem.cxx @@ -64,6 +64,13 @@ static Int_t *gLibraryVersion = 0; // Set in TVersionCheck, used in Load() static Int_t gLibraryVersionIdx = 0; // Set in TVersionCheck, used in Load() static Int_t gLibraryVersionMax = 256; +#if __cplusplus > 199711L +thread_local TString TSystem::fgLastErrorString; +#define LAST_ERROR_STRING fgLastErrorString +#else +#define LAST_ERROR_STRING fLastErrorString +#endif + ClassImp(TProcessEventTimer) //______________________________________________________________________________ @@ -246,7 +253,7 @@ void TSystem::SetErrorStr(const char *errstr) // library that does not use standard errno). ResetErrno(); // so GetError() uses the fLastErrorString - fLastErrorString = errstr; + LAST_ERROR_STRING = errstr; } //______________________________________________________________________________ @@ -254,8 +261,8 @@ const char *TSystem::GetError() { // Return system error string. - if (GetErrno() == 0 && fLastErrorString != "") - return fLastErrorString; + if (GetErrno() == 0 && LAST_ERROR_STRING != "") + return LAST_ERROR_STRING; return Form("errno: %d", GetErrno()); } diff --git a/core/base/src/TUUID.cxx b/core/base/src/TUUID.cxx index b5b7fade79c54..4e7c72a13d91e 100644 --- a/core/base/src/TUUID.cxx +++ b/core/base/src/TUUID.cxx @@ -111,6 +111,7 @@ #include "TInetAddress.h" #include "TMD5.h" #include "Bytes.h" +#include "TVirtualMutex.h" #include #include #ifdef R__WIN32 @@ -124,6 +125,7 @@ #endif #endif +#include ClassImp(TUUID) @@ -132,9 +134,9 @@ TUUID::TUUID() { // Create a UUID. - static uuid_time_t time_last; - static UShort_t clockseq; - static Bool_t firstTime = kTRUE; + static thread_local uuid_time_t time_last; + static thread_local UShort_t clockseq; + static thread_local Bool_t firstTime = kTRUE; if (firstTime) { if (gSystem) { // try to get a unique seed per process @@ -321,9 +323,9 @@ void TUUID::GetCurrentTime(uuid_time_t *timestamp) const UShort_t uuids_per_tick = 1024; - static uuid_time_t time_last; - static UShort_t uuids_this_tick; - static Bool_t init = kFALSE; + static thread_local uuid_time_t time_last; + static thread_local UShort_t uuids_this_tick; + static thread_local Bool_t init = kFALSE; if (!init) { GetSystemTime(&time_last); diff --git a/core/cont/src/TList.cxx b/core/cont/src/TList.cxx index 344d61678d622..99fa1a323fa72 100644 --- a/core/cont/src/TList.cxx +++ b/core/cont/src/TList.cxx @@ -69,6 +69,7 @@ #include "TList.h" #include "TClass.h" #include "TROOT.h" +#include "TVirtualMutex.h" #include namespace std {} using namespace std; @@ -360,8 +361,15 @@ void TList::Clear(Option_t *option) // list (of Primitives of the canvas) that was connecting it // (indirectly) to the list of cleanups. // So let's temporarily add the current list and remove it later. - bool needRegister = fFirst && TROOT::Initialized() && !gROOT->GetListOfCleanups()->FindObject(this); - if (needRegister) gROOT->GetListOfCleanups()->Add(this); + bool needRegister = fFirst && TROOT::Initialized(); + if(needRegister) { + R__LOCKGUARD2(gROOTMutex); + needRegister = needRegister && !gROOT->GetListOfCleanups()->FindObject(this); + } + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + gROOT->GetListOfCleanups()->Add(this); + } while (fFirst) { TObjLink *tlk = fFirst; fFirst = fFirst->Next(); @@ -376,7 +384,10 @@ void TList::Clear(Option_t *option) } delete tlk; } - if (needRegister) ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + } fFirst = fLast = fCache = 0; fSize = 0; Changed(); @@ -405,8 +416,15 @@ void TList::Delete(Option_t *option) // list (of Primitives of the canvas) that was connecting it // (indirectly) to the list of cleanups. // So let's temporarily add the current list and remove it later. - bool needRegister = fFirst && TROOT::Initialized() && !gROOT->GetListOfCleanups()->FindObject(this); - if (needRegister) gROOT->GetListOfCleanups()->Add(this); + bool needRegister = fFirst && TROOT::Initialized(); + if(needRegister) { + R__LOCKGUARD2(gROOTMutex); + needRegister = needRegister && !gROOT->GetListOfCleanups()->FindObject(this); + } + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + gROOT->GetListOfCleanups()->Add(this); + } while (fFirst) { TObjLink *tlk = fFirst; fFirst = fFirst->Next(); @@ -419,7 +437,12 @@ void TList::Delete(Option_t *option) delete tlk; } - if (needRegister) ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + } + fFirst = fLast = fCache = 0; fSize = 0; diff --git a/core/cont/src/TMap.cxx b/core/cont/src/TMap.cxx index d17cdc1f4bfa2..b88250b70b93a 100644 --- a/core/cont/src/TMap.cxx +++ b/core/cont/src/TMap.cxx @@ -278,16 +278,12 @@ void TMap::PrintCollectionEntry(TObject* entry, Option_t* option, Int_t recurse) printf("Key: "); entry->Print(); TROOT::IndentLevel(); - if (TStorage::IsOnHeap(val)) { - printf("Value: "); - TCollection* coll = dynamic_cast(val); - if (coll) { - coll->Print(option, recurse); - } else { - val->Print(option); - } + printf("Value: "); + TCollection* coll = dynamic_cast(val); + if (coll) { + coll->Print(option, recurse); } else { - printf("Value: 0x%lx\n", (ULong_t) val); + val->Print(option); } } diff --git a/core/cont/src/TObjArray.cxx b/core/cont/src/TObjArray.cxx index 0336f5970e29b..878907602a527 100644 --- a/core/cont/src/TObjArray.cxx +++ b/core/cont/src/TObjArray.cxx @@ -53,6 +53,7 @@ #include "TObjArray.h" #include "TError.h" #include "TROOT.h" +#include "TVirtualMutex.h" #include ClassImp(TObjArray) @@ -338,15 +339,25 @@ void TObjArray::Delete(Option_t *) // list (of Primitives of the canvas) that was connecting it // (indirectly) to the list of cleanups. // So let's temporarily add the current list and remove it later. - bool needRegister = fSize && TROOT::Initialized() && !gROOT->GetListOfCleanups()->FindObject(this); - if (needRegister) gROOT->GetListOfCleanups()->Add(this); + bool needRegister = fSize && TROOT::Initialized(); + if(needRegister) { + R__LOCKGUARD2(gROOTMutex); + needRegister = needRegister && !gROOT->GetListOfCleanups()->FindObject(this); + } + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + gROOT->GetListOfCleanups()->Add(this); + } for (Int_t i = 0; i < fSize; i++) { if (fCont[i] && fCont[i]->IsOnHeap()) { TCollection::GarbageCollect(fCont[i]); fCont[i] = 0; } } - if (needRegister) ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + if (needRegister) { + R__LOCKGUARD2(gROOTMutex); + ROOT::GetROOT()->GetListOfCleanups()->Remove(this); + } Init(fSize, fLowerBound); } diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h index 6088c8af6c906..62b9ed21e1ce5 100644 --- a/core/meta/inc/TClass.h +++ b/core/meta/inc/TClass.h @@ -35,7 +35,9 @@ #endif #include #include - +#if __cplusplus > 199711L +#include +#endif class TBaseClass; class TBrowser; class TDataMember; @@ -87,7 +89,11 @@ friend class ROOT::TGenericClassInfo; private: mutable TObjArray *fStreamerInfo; //Array of TVirtualStreamerInfo +#if __cplusplus > 199711L + mutable std::atomic*> fConversionStreamerInfo; //Array of the streamer infos derived from another class. +#else mutable std::map *fConversionStreamerInfo; //Array of the streamer infos derived from another class. +#endif TList *fRealData; //linked list for persistent members including base classes TList *fBase; //linked list for base classes TList *fData; //linked list for data members @@ -130,12 +136,20 @@ friend class ROOT::TGenericClassInfo; mutable Int_t fCanSplit; //!Indicates whether this class can be split or not. mutable Long_t fProperty; //!Property +#if __cplusplus > 199711L + mutable std::atomic fVersionUsed; //!Indicates whether GetClassVersion has been called +#else mutable Bool_t fVersionUsed; //!Indicates whether GetClassVersion has been called +#endif mutable Bool_t fIsOffsetStreamerSet; //!saved remember if fOffsetStreamer has been set. mutable Long_t fOffsetStreamer; //!saved info to call Streamer Int_t fStreamerType; //!cached of the streaming method to use +#if __cplusplus > 199711L + mutable std::atomic fCurrentInfo; //!cached current streamer info. +#else mutable TVirtualStreamerInfo *fCurrentInfo; //!cached current streamer info. +#endif TClassRef *fRefStart; //!List of references to this object TVirtualRefProxy *fRefProxy; //!Pointer to reference proxy if this class represents a reference ROOT::TSchemaRuleSet *fSchemaRules; //! Schema evolution rules @@ -155,6 +169,7 @@ friend class ROOT::TGenericClassInfo; void SetClassVersion(Version_t version); void SetClassSize(Int_t sizof) { fSizeof = sizof; } + TVirtualStreamerInfo* DetermineCurrentStreamerInfo(); // Various implementation for TClass::Stramer void StreamerExternal(void *object, TBuffer &b, const TClass *onfile_class) const; @@ -166,8 +181,13 @@ friend class ROOT::TGenericClassInfo; void StreamerDefault(void *object, TBuffer &b, const TClass *onfile_class) const; static IdMap_t *GetIdMap(); //Map from typeid to TClass pointer +#if __cplusplus > 199711L + static thread_local ENewType fgCallingNew; //Intent of why/how TClass::New() is called + static std::atomic fgClassCount; //provides unique id for a each class +#else static ENewType fgCallingNew; //Intent of why/how TClass::New() is called static Int_t fgClassCount; //provides unique id for a each class +#endif //stored in TObject::fUniqueID // Internal status bits enum { kLoading = BIT(14) }; @@ -267,7 +287,7 @@ friend class ROOT::TGenericClassInfo; const char *GetContextMenuTitle() const { return fContextMenuTitle; } TVirtualStreamerInfo *GetCurrentStreamerInfo() { if (fCurrentInfo) return fCurrentInfo; - else return (fCurrentInfo=(TVirtualStreamerInfo*)(fStreamerInfo->At(fClassVersion))); + else return DetermineCurrentStreamerInfo(); } TList *GetListOfDataMembers(); TList *GetListOfBases(); diff --git a/core/meta/inc/TVirtualStreamerInfo.h b/core/meta/inc/TVirtualStreamerInfo.h index 569d7e667ffd6..4d2add6bd81e3 100644 --- a/core/meta/inc/TVirtualStreamerInfo.h +++ b/core/meta/inc/TVirtualStreamerInfo.h @@ -60,7 +60,8 @@ class TVirtualStreamerInfo : public TNamed { kIgnoreTObjectStreamer = BIT(13), // eventhough BIT(13) is taken up by TObject (to preserverse forward compatibility) kRecovered = BIT(14), kNeedCheck = BIT(15), - kIsCompiled = BIT(16) + kIsCompiled = BIT(16), + kBuildOldUsed = BIT(17) }; enum EReadWrite { diff --git a/core/meta/src/TCint.cxx b/core/meta/src/TCint.cxx index 0e33edf7316d3..cf804e71dd9e5 100644 --- a/core/meta/src/TCint.cxx +++ b/core/meta/src/TCint.cxx @@ -2470,6 +2470,7 @@ Long_t TCint::GetExecByteCode() const Long_t TCint::Getgvp() const { // Interface to CINT function + R__LOCKGUARD(gCINTMutex); return (Long_t)G__getgvp(); } diff --git a/core/meta/src/TClass.cxx b/core/meta/src/TClass.cxx index 17bc164a009f9..de29906cb012b 100644 --- a/core/meta/src/TClass.cxx +++ b/core/meta/src/TClass.cxx @@ -92,14 +92,21 @@ namespace { }; } +#if __cplusplus > 199711L +std::atomic TClass::fgClassCount; +thread_local TClass::ENewType TClass::fgCallingNew = TClass::kRealNew; +#else Int_t TClass::fgClassCount; -TClass::ENewType TClass::fgCallingNew = kRealNew; +TClass::ENewType TClass::fgCallingNew = TClass::kRealNew; +#endif struct ObjRepoValue { ObjRepoValue(const TClass *what, Version_t version) : fClass(what),fVersion(version) {} const TClass *fClass; Version_t fVersion; }; + +static TVirtualMutex* gOVRMutex = 0; typedef std::multimap RepoCont_t; static RepoCont_t gObjectVersionRepository; @@ -113,8 +120,10 @@ static void RegisterAddressInRepository(const char * /*where*/, void *location, // } else { // Warning(where, "Registering address %p again of class '%s' version %d", location, what->GetName(), version); // } - gObjectVersionRepository.insert(RepoCont_t::value_type(location, RepoCont_t::mapped_type(what,version))); - + { + R__LOCKGUARD2(gOVRMutex); + gObjectVersionRepository.insert(RepoCont_t::value_type(location, RepoCont_t::mapped_type(what,version))); + } #if 0 // This code could be used to prevent an address to be registered twice. std::pair tmp = gObjectVersionRepository.insert(RepoCont_t::value_type>(location, RepoCont_t::mapped_type(what,version))); @@ -133,6 +142,7 @@ static void UnregisterAddressInRepository(const char * /*where*/, void *location { // Remove an address from the repository of address/object. + R__LOCKGUARD2(gOVRMutex); RepoCont_t::iterator cur = gObjectVersionRepository.find(location); for (; cur != gObjectVersionRepository.end();) { RepoCont_t::iterator tmp = cur++; @@ -154,6 +164,7 @@ static void MoveAddressInRepository(const char * /*where*/, void *oldadd, void * // Move not only the object itself but also any base classes or sub-objects. size_t objsize = what->Size(); long delta = (char*)newadd - (char*)oldadd; + R__LOCKGUARD2(gOVRMutex); RepoCont_t::iterator cur = gObjectVersionRepository.find(oldadd); for (; cur != gObjectVersionRepository.end();) { RepoCont_t::iterator tmp = cur++; @@ -264,6 +275,8 @@ void TClass::AddClass(TClass *cl) // static: Add a class to the list and map of classes. if (!cl) return; + + R__LOCKGUARD2(gCINTMutex); gROOT->GetListOfClasses()->Add(cl); if (cl->GetTypeInfo()) { GetIdMap()->Add(cl->GetTypeInfo()->name(),cl); @@ -277,6 +290,8 @@ void TClass::RemoveClass(TClass *oldcl) // static: Remove a class from the list and map of classes if (!oldcl) return; + + R__LOCKGUARD2(gCINTMutex); gROOT->GetListOfClasses()->Remove(oldcl); if (oldcl->GetTypeInfo()) { GetIdMap()->Remove(oldcl->GetTypeInfo()->name()); @@ -1116,7 +1131,7 @@ void TClass::Init(const char *name, Version_t cversion, TClass::TClass(const TClass& cl) : TDictionary(cl), fStreamerInfo(cl.fStreamerInfo), - fConversionStreamerInfo(cl.fConversionStreamerInfo), + fConversionStreamerInfo(0), fRealData(cl.fRealData), fBase(cl.fBase), fData(cl.fData), @@ -1155,15 +1170,15 @@ TClass::TClass(const TClass& cl) : fSizeof(cl.fSizeof), fCanSplit(cl.fCanSplit), fProperty(cl.fProperty), - fVersionUsed(cl.fVersionUsed), + fVersionUsed(), fIsOffsetStreamerSet(cl.fIsOffsetStreamerSet), fOffsetStreamer(cl.fOffsetStreamer), fStreamerType(cl.fStreamerType), - fCurrentInfo(cl.fCurrentInfo), + fCurrentInfo(0), fRefStart(cl.fRefStart), fRefProxy(cl.fRefProxy), fSchemaRules(cl.fSchemaRules), - fStreamerImpl(cl.fStreamerImpl) + fStreamerImpl(0) { //copy constructor @@ -1274,11 +1289,15 @@ TClass::~TClass() delete fSchemaRules; if (fConversionStreamerInfo) { std::map::iterator it; - std::map::iterator end = fConversionStreamerInfo->end(); - for( it = fConversionStreamerInfo->begin(); it != end; ++it ) { + std::map::iterator end = (*fConversionStreamerInfo).end(); + for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) { delete it->second; } +#if __cplusplus > 199711L + delete fConversionStreamerInfo.load(); +#else delete fConversionStreamerInfo; +#endif } } @@ -2035,6 +2054,9 @@ TObject *TClass::Clone(const char *new_name) const Error("Clone","The name of the class must be changed when cloning a TClass object."); return 0; } + + // Need to lock access to TROOT::GetListOfClasses so the cloning happens atomically + R__LOCKGUARD2(gCINTMutex); // Temporarily remove the original from the list of classes. TClass::RemoveClass(const_cast(this)); @@ -2343,13 +2365,17 @@ Int_t TClass::GetBaseClassOffsetRecurse(const TClass *cl) c = inh->GetClassPointer(kTRUE); // kFALSE); if (c) { if (cl == c) { - if ((inh->Property() & G__BIT_ISVIRTUALBASE) != 0) - return -2; + R__LOCKGUARD(gCINTMutex); + if ((inh->Property() & G__BIT_ISVIRTUALBASE) != 0) + return -2; return inh->GetDelta(); } off = c->GetBaseClassOffsetRecurse(cl); if (off == -2) return -2; - if (off != -1) return off + inh->GetDelta(); + if (off != -1) { + R__LOCKGUARD(gCINTMutex); + return off + inh->GetDelta(); + } } lnk = lnk->Next(); } @@ -2677,6 +2703,9 @@ TClass *TClass::GetClass(const type_info& typeinfo, Bool_t load, Bool_t /* silen { // Return pointer to class with name. + //protect access to TROOT::GetListOfClasses + R__LOCKGUARD2(gCINTMutex); + if (!gROOT->GetListOfClasses()) return 0; //printf("TClass::GetClass called, typeinfo.name=%s\n",typeinfo.name()); @@ -2987,7 +3016,10 @@ TList *TClass::GetListOfBases() if (!gInterpreter) Fatal("GetListOfBases", "gInterpreter not initialized"); - gInterpreter->CreateListOfBaseClasses(this); + R__LOCKGUARD(gCINTMutex); + if(!fBase) { + gInterpreter->CreateListOfBaseClasses(this); + } } return fBase; } @@ -3278,8 +3310,8 @@ void TClass::ls(Option_t *options) const if (fConversionStreamerInfo) { std::map::iterator it; - std::map::iterator end = fConversionStreamerInfo->end(); - for( it = fConversionStreamerInfo->begin(); it != end; ++it ) { + std::map::iterator end = (*fConversionStreamerInfo).end(); + for( it = (*fConversionStreamerInfo).begin(); it != end; ++it ) { it->second->ls(options); } } @@ -3914,8 +3946,9 @@ void *TClass::New(ENewType defConstructor) const // FIXME: Partial Answer: Is this because we may never actually deregister them??? Bool_t statsave = GetObjectStat(); - SetObjectStat(kFALSE); - + if(statsave) { + SetObjectStat(kFALSE); + } TVirtualStreamerInfo* sinfo = GetStreamerInfo(); if (!sinfo) { Error("New", "Cannot construct class '%s' version %d, no streamer info available!", GetName(), fClassVersion); @@ -3928,7 +3961,9 @@ void *TClass::New(ENewType defConstructor) const // FIXME: Mistake? See note above at the GetObjectStat() call. // Allow TObject's to be registered again. - SetObjectStat(statsave); + if(statsave) { + SetObjectStat(statsave); + } // Register the object for special handling in the destructor. if (p) { @@ -3997,7 +4032,9 @@ void *TClass::New(void *arena, ENewType defConstructor) const // Do not register any TObject's that we create // as a result of creating this object. Bool_t statsave = GetObjectStat(); - SetObjectStat(kFALSE); + if(statsave) { + SetObjectStat(kFALSE); + } TVirtualStreamerInfo* sinfo = GetStreamerInfo(); if (!sinfo) { @@ -4011,7 +4048,9 @@ void *TClass::New(void *arena, ENewType defConstructor) const // ???BUG??? // Allow TObject's to be registered again. - SetObjectStat(statsave); + if(statsave) { + SetObjectStat(statsave); + } // Register the object for special handling in the destructor. if (p) { @@ -4081,7 +4120,9 @@ void *TClass::NewArray(Long_t nElements, ENewType defConstructor) const // Do not register any TObject's that we create // as a result of creating this object. Bool_t statsave = GetObjectStat(); - SetObjectStat(kFALSE); + if(statsave) { + SetObjectStat(kFALSE); + } TVirtualStreamerInfo* sinfo = GetStreamerInfo(); if (!sinfo) { @@ -4095,7 +4136,9 @@ void *TClass::NewArray(Long_t nElements, ENewType defConstructor) const // ???BUG??? // Allow TObject's to be registered again. - SetObjectStat(statsave); + if(statsave) { + SetObjectStat(statsave); + } // Register the object for special handling in the destructor. if (p) { @@ -4164,7 +4207,9 @@ void *TClass::NewArray(Long_t nElements, void *arena, ENewType defConstructor) c // Do not register any TObject's that we create // as a result of creating this object. Bool_t statsave = GetObjectStat(); - SetObjectStat(kFALSE); + if(statsave) { + SetObjectStat(kFALSE); + } TVirtualStreamerInfo* sinfo = GetStreamerInfo(); if (!sinfo) { @@ -4178,7 +4223,9 @@ void *TClass::NewArray(Long_t nElements, void *arena, ENewType defConstructor) c // ???BUG??? // Allow TObject's to be registered again. - SetObjectStat(statsave); + if(statsave) { + SetObjectStat(statsave); + } if (fStreamerType & kEmulated) { // We always register emulated objects, we need to always @@ -4222,8 +4269,10 @@ void TClass::Destructor(void *obj, Bool_t dtorOnly) // or it will be interpreted, otherwise we fail // because there is no destructor code at all. if (dtorOnly) { + R__LOCKGUARD2(gCINTMutex); gCint->ClassInfo_Destruct(fClassInfo,p); } else { + R__LOCKGUARD2(gCINTMutex); gCint->ClassInfo_Delete(fClassInfo,p); } } else if (!fClassInfo && fCollectionProxy) { @@ -4242,20 +4291,24 @@ void TClass::Destructor(void *obj, Bool_t dtorOnly) // Was this object allocated through TClass? std::multiset knownVersions; - RepoCont_t::iterator iter = gObjectVersionRepository.find(p); - if (iter == gObjectVersionRepository.end()) { - // No, it wasn't, skip special version handling. - //Error("Destructor2", "Attempt to delete unregistered object of class '%s' at address %p!", GetName(), p); - inRepo = kFALSE; - } else { - //objVer = iter->second; - for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) { - Version_t ver = iter->second.fVersion; - knownVersions.insert(ver); - if (ver == fClassVersion && this == iter->second.fClass) { - verFound = kTRUE; - } - } + R__LOCKGUARD2(gOVRMutex); + + { + RepoCont_t::iterator iter = gObjectVersionRepository.find(p); + if (iter == gObjectVersionRepository.end()) { + // No, it wasn't, skip special version handling. + //Error("Destructor2", "Attempt to delete unregistered object of class '%s' at address %p!", GetName(), p); + inRepo = kFALSE; + } else { + //objVer = iter->second; + for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) { + Version_t ver = iter->second.fVersion; + knownVersions.insert(ver); + if (ver == fClassVersion && this == iter->second.fClass) { + verFound = kTRUE; + } + } + } } if (!inRepo || verFound) { @@ -4353,19 +4406,22 @@ void TClass::DeleteArray(void *ary, Bool_t dtorOnly) // Was this array object allocated through TClass? std::multiset knownVersions; - RepoCont_t::iterator iter = gObjectVersionRepository.find(p); - if (iter == gObjectVersionRepository.end()) { - // No, it wasn't, we cannot know what to do. - //Error("DeleteArray", "Attempt to delete unregistered array object, element type '%s', at address %p!", GetName(), p); - inRepo = kFALSE; - } else { - for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) { - Version_t ver = iter->second.fVersion; - knownVersions.insert(ver); - if (ver == fClassVersion && this == iter->second.fClass ) { - verFound = kTRUE; - } - } + { + R__LOCKGUARD2(gOVRMutex); + RepoCont_t::iterator iter = gObjectVersionRepository.find(p); + if (iter == gObjectVersionRepository.end()) { + // No, it wasn't, we cannot know what to do. + //Error("DeleteArray", "Attempt to delete unregistered array object, element type '%s', at address %p!", GetName(), p); + inRepo = kFALSE; + } else { + for (; (iter != gObjectVersionRepository.end()) && (iter->first == p); ++iter) { + Version_t ver = iter->second.fVersion; + knownVersions.insert(ver); + if (ver == fClassVersion && this == iter->second.fClass ) { + verFound = kTRUE; + } + } + } } if (!inRepo || verFound) { @@ -4454,6 +4510,18 @@ void TClass::SetClassVersion(Version_t version) fCurrentInfo = 0; } +//______________________________________________________________________________ +TVirtualStreamerInfo* TClass::DetermineCurrentStreamerInfo() +{ + // Determine and set pointer to current TVirtualStreamerInfo + + R__LOCKGUARD2(gCINTMutex); + if(!fCurrentInfo) { + fCurrentInfo=(TVirtualStreamerInfo*)(fStreamerInfo->At(fClassVersion)); + } + return fCurrentInfo; +} + //______________________________________________________________________________ void TClass::SetCurrentStreamerInfo(TVirtualStreamerInfo *info) { @@ -4613,6 +4681,8 @@ void TClass::PostLoadCheck() } else if (IsLoaded() && fClassInfo && fStreamerInfo && (!IsForeign()||fClassVersion>1) ) { + R__LOCKGUARD(gCINTMutex); + TVirtualStreamerInfo *info = (TVirtualStreamerInfo*)(fStreamerInfo->At(fClassVersion)); // Here we need to check whether this TVirtualStreamerInfo (which presumably has been // loaded from a file) is consistent with the definition in the library we just loaded. @@ -5369,6 +5439,7 @@ TVirtualStreamerInfo *TClass::FindStreamerInfo(UInt_t checksum) const { // Find the TVirtualStreamerInfo in the StreamerInfos corresponding to checksum + R__LOCKGUARD(gCINTMutex); Int_t ninfos = fStreamerInfo->GetEntriesFast()-1; for (Int_t i=-1;iGetEntriesFast()-1; for (Int_t i=-1;i::iterator it; + R__LOCKGUARD(gCINTMutex); - it = fConversionStreamerInfo->find( cl->GetName() ); + it = (*fConversionStreamerInfo).find( cl->GetName() ); - if( it != fConversionStreamerInfo->end() ) { + if( it != (*fConversionStreamerInfo).end() ) { arr = it->second; } @@ -5527,10 +5599,11 @@ TVirtualStreamerInfo *TClass::FindConversionStreamerInfo( const TClass* cl, UInt TVirtualStreamerInfo* info = 0; if (fConversionStreamerInfo) { std::map::iterator it; + R__LOCKGUARD(gCINTMutex); + + it = (*fConversionStreamerInfo).find( cl->GetName() ); - it = fConversionStreamerInfo->find( cl->GetName() ); - - if( it != fConversionStreamerInfo->end() ) { + if( it != (*fConversionStreamerInfo).end() ) { arr = it->second; } if (arr) { diff --git a/core/meta/src/TSchemaRuleSet.cxx b/core/meta/src/TSchemaRuleSet.cxx index ee78797e749e0..18cb1a446b4f8 100644 --- a/core/meta/src/TSchemaRuleSet.cxx +++ b/core/meta/src/TSchemaRuleSet.cxx @@ -11,6 +11,8 @@ #include "TVirtualCollectionProxy.h" #include "TVirtualStreamerInfo.h" +#include "TVirtualMutex.h" +#include "TInterpreter.h" // For gCINTMutex #include "TStreamerElement.h" #include "TClassEdit.h" @@ -103,7 +105,12 @@ Bool_t TSchemaRuleSet::AddRule( TSchemaRule* rule, EConsistencyCheck checkConsis TObject* obj; // Check only if we have some information about the class, otherwise we have // nothing to check against - if( rule->GetTarget() && !(fClass->TestBit(TClass::kIsEmulation) && (fClass->GetStreamerInfos()==0 || fClass->GetStreamerInfos()->GetEntries()==0)) ) { + bool streamerInfosTest; + { + R__LOCKGUARD2(gCINTMutex); + streamerInfosTest = (fClass->GetStreamerInfos()==0 || fClass->GetStreamerInfos()->GetEntries()==0); + } + if( rule->GetTarget() && !(fClass->TestBit(TClass::kIsEmulation) && streamerInfosTest) ) { TObjArrayIter titer( rule->GetTarget() ); while( (obj = titer.Next()) ) { TObjString* str = (TObjString*)obj; diff --git a/core/meta/src/TStreamerElement.cxx b/core/meta/src/TStreamerElement.cxx index 52b8c631785a0..2f4bfbe3fae07 100644 --- a/core/meta/src/TStreamerElement.cxx +++ b/core/meta/src/TStreamerElement.cxx @@ -39,7 +39,12 @@ namespace std {} using namespace std; const Int_t kMaxLen = 1024; + +#if __cplusplus > 199711L +static thread_local TString gIncludeName(kMaxLen); +#else static TString gIncludeName(kMaxLen); +#endif extern void *gMmallocDesc; @@ -295,7 +300,11 @@ const char *TStreamerElement::GetFullName() const // Note that this function stores the name into a static array. // You should copy the result. +#if __cplusplus > 199711L + static thread_local TString name(kMaxLen); +#else static TString name(kMaxLen); +#endif char cdim[20]; name = GetName(); for (Int_t i=0;iGetStreamerInfos(); - TVirtualStreamerInfo *info = (TVirtualStreamerInfo *)sinfos->At(cl->GetClassVersion()); + TVirtualStreamerInfo *info; + { + R__LOCKGUARD(gCINTMutex); + TObjArray *sinfos = cl->GetStreamerInfos(); + info = (TVirtualStreamerInfo *)sinfos->At(cl->GetClassVersion()); + } if (!info || !info->IsBuilt()) { // Even if the streamerInfo exist, it could still need to be 'build' diff --git a/core/thread/src/TThread.cxx b/core/thread/src/TThread.cxx index bfb185176b4be..d06b0716ee710 100644 --- a/core/thread/src/TThread.cxx +++ b/core/thread/src/TThread.cxx @@ -300,6 +300,16 @@ void TThread::Init() gGlobalMutex = new TMutex(kTRUE); gCint->SetAlloclockfunc(CINT_alloc_lock); gCint->SetAllocunlockfunc(CINT_alloc_unlock); + + //To avoid deadlocks, gCintMutex and gROOTMutex need + // to point at the same instance + { + R__LOCKGUARD(gGlobalMutex); + if (!gCINTMutex) { + gCINTMutex = gGlobalMutex->Factory(kTRUE); + } + gROOTMutex = gCINTMutex; + } } //______________________________________________________________________________ diff --git a/core/unix/src/TUnixSystem.cxx b/core/unix/src/TUnixSystem.cxx index e22c9d1227e86..a26b8ef8318c9 100644 --- a/core/unix/src/TUnixSystem.cxx +++ b/core/unix/src/TUnixSystem.cxx @@ -37,6 +37,9 @@ #include "TVirtualMutex.h" #include "TObjArray.h" #include +#if __cplusplus > 199711L +#include +#endif //#define G__OLDEXPAND @@ -438,7 +441,11 @@ static void SigHandler(ESignals sig) //______________________________________________________________________________ static const char *GetExePath() { +#if __cplusplus > 199711L + static thread_local TString exepath; +#else static TString exepath; +#endif if (exepath == "") { #if defined(R__MACOSX) exepath = _dyld_get_image_name(0); @@ -582,6 +589,11 @@ static void DylibAdded(const struct mach_header *mh, intptr_t /* vmaddr_slide */ } #endif +#if __cplusplus > 199711L +#define LAST_ERROR_STRING fgLastErrorString +#else +#define LAST_ERROR_STRING fLastErrorString +#endif ClassImp(TUnixSystem) @@ -727,8 +739,9 @@ const char *TUnixSystem::GetError() // Return system error string. Int_t err = GetErrno(); - if (err == 0 && fLastErrorString != "") - return fLastErrorString; + if (err == 0 && LAST_ERROR_STRING != "") + return LAST_ERROR_STRING; + #if defined(R__SOLARIS) || defined (R__LINUX) || defined(R__AIX) || \ defined(R__FBSD) || defined(R__OBSD) || defined(R__HURD) return strerror(err); @@ -1576,7 +1589,8 @@ Bool_t TUnixSystem::AccessPathName(const char *path, EAccessMode mode) if (::access(StripOffProto(path, "file:"), mode) == 0) return kFALSE; - fLastErrorString = GetError(); + LAST_ERROR_STRING = GetError(); + return kTRUE; } @@ -1623,7 +1637,7 @@ int TUnixSystem::Rename(const char *f, const char *t) // Rename a file. Returns 0 when successful, -1 in case of failure. int ret = ::rename(f, t); - fLastErrorString = GetError(); + LAST_ERROR_STRING = GetError(); return ret; } @@ -1825,7 +1839,7 @@ Bool_t TUnixSystem::ExpandPathName(TString &patbuf0) } else { hd = UnixHomedirectory(0); if (hd == 0) { - fLastErrorString = GetError(); + LAST_ERROR_STRING = GetError(); return kTRUE; } cmd += hd; @@ -1835,7 +1849,7 @@ Bool_t TUnixSystem::ExpandPathName(TString &patbuf0) cmd += stuffedPat; if ((pf = ::popen(cmd.Data(), "r")) == 0) { - fLastErrorString = GetError(); + LAST_ERROR_STRING = GetError(); return kTRUE; } @@ -1858,7 +1872,7 @@ Bool_t TUnixSystem::ExpandPathName(TString &patbuf0) while (ch != EOF) { ch = fgetc(pf); if (ch == ' ' || ch == '\t') { - fLastErrorString = "expression ambigous"; + LAST_ERROR_STRING = "expression ambigous"; ::pclose(pf); return kTRUE; } @@ -3769,8 +3783,13 @@ void TUnixSystem::UnixIgnoreSignal(ESignals sig, Bool_t ignr) // If ignr is true ignore the specified signal, else restore previous // behaviour. +#if __cplusplus > 199711L + static thread_local Bool_t ignoreSig[kMAXSIGNALS] = { kFALSE }; + static thread_local struct sigaction oldsigact[kMAXSIGNALS]; +#else static Bool_t ignoreSig[kMAXSIGNALS] = { kFALSE }; static struct sigaction oldsigact[kMAXSIGNALS]; +#endif if (ignr != ignoreSig[sig]) { ignoreSig[sig] = ignr; @@ -3874,7 +3893,11 @@ Long64_t TUnixSystem::UnixNow() { // Get current time in milliseconds since 0:00 Jan 1 1995. +#if __cplusplus > 199711L + static std::atomic jan95{0}; +#else static time_t jan95 = 0; +#endif if (!jan95) { struct tm tp; tp.tm_year = 95; diff --git a/core/utils/src/rootcint.cxx b/core/utils/src/rootcint.cxx index 43ff08dab1e82..ab5b862ae9e95 100644 --- a/core/utils/src/rootcint.cxx +++ b/core/utils/src/rootcint.cxx @@ -2398,7 +2398,7 @@ void WriteClassFunctions(G__ClassInfo &cl, int /*tmplt*/ = 0) (*dictSrcOut) << "//_______________________________________" << "_______________________________________" << std::endl; if (add_template_keyword) (*dictSrcOut) << "template <> "; - (*dictSrcOut) << "TClass *" << clsname.c_str() << "::fgIsA = 0; // static to hold class pointer" << std::endl + (*dictSrcOut) << "atomic_TClass_ptr " << clsname.c_str() << "::fgIsA(0); // static to hold class pointer" << std::endl << std::endl << "//_______________________________________" @@ -2433,8 +2433,8 @@ void WriteClassFunctions(G__ClassInfo &cl, int /*tmplt*/ = 0) << "_______________________________________" << std::endl; if (add_template_keyword) (*dictSrcOut) << "template <> "; (*dictSrcOut) << "TClass *" << clsname.c_str() << "::Class()" << std::endl << "{" << std::endl; - (*dictSrcOut) << " if (!fgIsA) fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::"; - (*dictSrcOut) << cl.Fullname() << "*)0x0)->GetClass();" << std::endl + (*dictSrcOut) << " if (!fgIsA) { R__LOCKGUARD2(gCINTMutex); if(!fgIsA) {fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::"; + (*dictSrcOut) << cl.Fullname() << "*)0x0)->GetClass();} }" << std::endl << " return fgIsA;" << std::endl << "}" << std::endl << std::endl; @@ -4942,6 +4942,8 @@ int main(int argc, char **argv) (*dictSrcOut) << "#include \"TClass.h\"" << std::endl << "#include \"TBuffer.h\"" << std::endl << "#include \"TMemberInspector.h\"" << std::endl + << "#include \"TInterpreter.h\"" << std::endl + << "#include \"TVirtualMutex.h\"" << std::endl << "#include \"TError.h\"" << std::endl << std::endl << "#ifndef G__ROOT" << std::endl << "#define G__ROOT" << std::endl diff --git a/core/utils/src/rootcling.cxx b/core/utils/src/rootcling.cxx index 4ea7ae2a79e0f..46acb8318d806 100644 --- a/core/utils/src/rootcling.cxx +++ b/core/utils/src/rootcling.cxx @@ -3483,7 +3483,7 @@ void WriteClassFunctions(const clang::CXXRecordDecl *cl) (*dictSrcOut) << "//_______________________________________" << "_______________________________________" << std::endl; if (add_template_keyword) (*dictSrcOut) << "template <> "; - (*dictSrcOut) << "TClass *" << clsname.c_str() << "::fgIsA = 0; // static to hold class pointer" << std::endl + (*dictSrcOut) << "atomic_TClass_ptr " << clsname.c_str() << "::fgIsA(0); // static to hold class pointer" << std::endl << std::endl << "//_______________________________________" @@ -3518,8 +3518,8 @@ void WriteClassFunctions(const clang::CXXRecordDecl *cl) << "_______________________________________" << std::endl; if (add_template_keyword) (*dictSrcOut) << "template <> "; (*dictSrcOut) << "TClass *" << clsname.c_str() << "::Class()" << std::endl << "{" << std::endl; - (*dictSrcOut) << " if (!fgIsA) fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::"; - (*dictSrcOut) << fullname.c_str() << "*)0x0)->GetClass();" << std::endl + (*dictSrcOut) << " if (!fgIsA) { R__LOCKGUARD2(gCINTMutex); if(!fgIsA) {fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::"; + (*dictSrcOut) << fullname.c_str() << "*)0x0)->GetClass();} }" << std::endl << " return fgIsA;" << std::endl << "}" << std::endl << std::endl; @@ -6514,6 +6514,8 @@ int main(int argc, char **argv) << "#include \"TCintWithCling.h\"" << std::endl << "#include \"TBuffer.h\"" << std::endl << "#include \"TMemberInspector.h\"" << std::endl + << "#include \"TInterpreter.h\"" << std::endl + << "#include \"TVirtualMutex.h\"" << std::endl << "#include \"TError.h\"" << std::endl << std::endl << "#ifndef G__ROOT" << std::endl << "#define G__ROOT" << std::endl diff --git a/core/zip/inc/Bits.h b/core/zip/inc/Bits.h index fafb888107f56..b24de20c4efba 100644 --- a/core/zip/inc/Bits.h +++ b/core/zip/inc/Bits.h @@ -89,9 +89,9 @@ local void R__flush_outbuf OF((unsigned w, unsigned size)); /* =========================================================================== * Local data used by the "bit string" routines. */ -local FILE *zfile; /* output zip file */ +local __thread FILE *zfile; /* output zip file */ -local unsigned short bi_buf; +local __thread unsigned short bi_buf; /* Output buffer. bits are inserted starting at the bottom (least significant * bits). */ @@ -101,25 +101,25 @@ local unsigned short bi_buf; * more than 16 bits on some systems.) */ -local int bi_valid; +local __thread int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ -local char *in_buf, *out_buf; +local __thread char *in_buf, *out_buf; /* Current input and output buffers. in_buf is used only for in-memory * compression. */ -local unsigned in_offset, out_offset; +local __thread unsigned in_offset, out_offset; /* Current offset in input and output buffers. in_offset is used only for * in-memory compression. On 16 bit machiens, the buffer is limited to 64K. */ -local unsigned in_size, out_size; +local __thread unsigned in_size, out_size; /* Size of current input and output buffers */ -int (*R__read_buf) OF((char *buf, unsigned size)) = R__mem_read; +__thread int (*R__read_buf) OF((char *buf, unsigned size)) = R__mem_read; /* Current input function. Set to R__mem_read for in-memory compression */ #ifdef DEBUG @@ -411,7 +411,7 @@ local int R__mem_read(char *b, unsigned bsize) * * ***********************************************************************/ #define HDRSIZE 9 -static int error_flag; +static __thread int error_flag; void R__zipMultipleAlgorithm(int cxlevel, int *srcsize, char *src, int *tgtsize, char *tgt, int *irep, int compressionAlgorithm) /* int cxlevel; compression level */ @@ -496,6 +496,8 @@ void R__zipMultipleAlgorithm(int cxlevel, int *srcsize, char *src, int *tgtsize, } else { z_stream stream; + //Don't use the globals but want name similar to help see similarities in code + unsigned l_in_size, l_out_size; *irep = 0; error_flag = 0; @@ -538,15 +540,15 @@ void R__zipMultipleAlgorithm(int cxlevel, int *srcsize, char *src, int *tgtsize, tgt[1] = 'L'; tgt[2] = (char) method; - in_size = (unsigned) (*srcsize); - out_size = stream.total_out; /* compressed size */ - tgt[3] = (char)(out_size & 0xff); - tgt[4] = (char)((out_size >> 8) & 0xff); - tgt[5] = (char)((out_size >> 16) & 0xff); + l_in_size = (unsigned) (*srcsize); + l_out_size = stream.total_out; /* compressed size */ + tgt[3] = (char)(l_out_size & 0xff); + tgt[4] = (char)((l_out_size >> 8) & 0xff); + tgt[5] = (char)((l_out_size >> 16) & 0xff); - tgt[6] = (char)(in_size & 0xff); /* decompressed size */ - tgt[7] = (char)((in_size >> 8) & 0xff); - tgt[8] = (char)((in_size >> 16) & 0xff); + tgt[6] = (char)(l_in_size & 0xff); /* decompressed size */ + tgt[7] = (char)((l_in_size >> 8) & 0xff); + tgt[8] = (char)((l_in_size >> 16) & 0xff); *irep = stream.total_out + HDRSIZE; return; diff --git a/core/zip/inc/ZIP.h b/core/zip/inc/ZIP.h index b644341665afb..41f46184eccf5 100644 --- a/core/zip/inc/ZIP.h +++ b/core/zip/inc/ZIP.h @@ -110,7 +110,7 @@ unsigned R__bi_reverse OF((unsigned value, int length)); void R__bi_windup OF((void)); void R__copy_block OF((char far *buf, unsigned len, int header)); int R__seekable OF((void)); -extern int (*R__read_buf) OF((char *buf, unsigned size)); +extern __thread int (*R__read_buf) OF((char *buf, unsigned size)); ulg R__memcompress OF((char *tgt, ulg tgtsize, char *src, ulg srcsize)); void R__error OF((char *h)); diff --git a/etc/valgrind-root.supp b/etc/valgrind-root.supp index 019624d5fa0ae..1cf82fc3b6f74 100644 --- a/etc/valgrind-root.supp +++ b/etc/valgrind-root.supp @@ -484,6 +484,29 @@ fun:_ZL20G__cpp_setup_global0v } +######## ROOT TObject on heap + +{ + TObject::TObject() uses uninitialized value + Memcheck:Cond + fun:_ZN7TObjectC1Ev + ... +} + +{ + TObject::TObject(const TObject&) uses uninitialized value + Memcheck:Cond + fun:_ZN7TObjectC1ERKS_ + ... +} + +{ + gcc optimizer confuses valgrind on TObject::~TObject() + Memcheck:Cond + fun:_ZN7TObjectD1Ev + ... +} + ######### Misc { diff --git a/hist/hbook/src/THbookFile.cxx b/hist/hbook/src/THbookFile.cxx index bafecd94aa2ce..89ee64eb6f4f7 100644 --- a/hist/hbook/src/THbookFile.cxx +++ b/hist/hbook/src/THbookFile.cxx @@ -236,7 +236,7 @@ extern "C" void type_of_call hldir(DEFCHAR,DEFCHAR); Bool_t THbookFile::fgPawInit = kFALSE; Int_t *THbookFile::fgLuns = 0; -R__EXTERN TTree *gTree; +R__EXTERN thread_local TTree *gTree; ClassImp(THbookFile) diff --git a/io/io/inc/TFile.h b/io/io/inc/TFile.h index 9018215336d0e..1f22a8a3f9fde 100644 --- a/io/io/inc/TFile.h +++ b/io/io/inc/TFile.h @@ -21,6 +21,9 @@ // // ////////////////////////////////////////////////////////////////////////// +#if __cplusplus > 199711L +#include +#endif #ifndef ROOT_TDirectoryFile #include "TDirectoryFile.h" #endif @@ -104,13 +107,20 @@ class TFile : public TDirectoryFile { static Bool_t fgCacheFileForce; //Indicates, to force all READ to CACHEREAD static UInt_t fgOpenTimeout; //Timeout for open operations in ms - 0 corresponds to blocking i/o static Bool_t fgOnlyStaged ; //Before the file is opened, it is checked, that the file is staged, if not, the open fails + +#if __cplusplus > 199711L + static std::atomic fgBytesWrite; //Number of bytes written by all TFile objects + static std::atomic fgBytesRead; //Number of bytes read by all TFile objects + static std::atomic fgFileCounter; //Counter for all opened files + static std::atomic fgReadCalls; //Number of bytes read from all TFile objects +#else static Long64_t fgBytesWrite; //Number of bytes written by all TFile objects static Long64_t fgBytesRead; //Number of bytes read by all TFile objects static Long64_t fgFileCounter; //Counter for all opened files static Int_t fgReadCalls; //Number of bytes read from all TFile objects +#endif static Int_t fgReadaheadSize; //Readahead buffer size static Bool_t fgReadInfo; //if true (default) ReadStreamerInfo is called when opening a file - virtual EAsyncOpenStatus GetAsyncOpenStatus() { return fAsyncOpenStatus; } virtual void Init(Bool_t create); Bool_t FlushWriteCache(); diff --git a/io/io/inc/TStreamerInfo.h b/io/io/inc/TStreamerInfo.h index 044538ba77ffc..87528fbb4e5fb 100644 --- a/io/io/inc/TStreamerInfo.h +++ b/io/io/inc/TStreamerInfo.h @@ -20,6 +20,9 @@ // Describe Streamer information for one class version // // // ////////////////////////////////////////////////////////////////////////// +#if __cplusplus > 199711L +#include +#endif #ifndef ROOT_TVirtualStreamerInfo #include "TVirtualStreamerInfo.h" @@ -104,15 +107,23 @@ class TStreamerInfo : public TVirtualStreamerInfo { Version_t fOldVersion; //! Version of the TStreamerInfo object read from the file Int_t fNVirtualInfoLoc; //! Number of virtual info location to update. ULong_t *fVirtualInfoLoc; //![fNVirtualInfoLoc] Location of the pointer to the TStreamerInfo inside the object (when emulated) +#if __cplusplus > 199711L + std::atomic fLiveCount; //! Number of outstanding pointer to this StreamerInfo. +#else ULong_t fLiveCount; //! Number of outstanding pointer to this StreamerInfo. - +#endif TStreamerInfoActions::TActionSequence *fReadObjectWise; //! List of read action resulting from the compilation. TStreamerInfoActions::TActionSequence *fReadMemberWise; //! List of read action resulting from the compilation for use in member wise streaming. TStreamerInfoActions::TActionSequence *fWriteObjectWise; //! List of write action resulting from the compilation. TStreamerInfoActions::TActionSequence *fWriteMemberWise; //! List of write action resulting from the compilation for use in member wise streaming. +#if __cplusplus > 199711L + static std::atomic fgCount; //Number of TStreamerInfo instances + static thread_local TStreamerElement *fgElement; //Pointer to current TStreamerElement +#else static Int_t fgCount; //Number of TStreamerInfo instances static TStreamerElement *fgElement; //Pointer to current TStreamerElement +#endif template static T GetTypedValueAux(Int_t type, void *ladd, int k, Int_t len); static void PrintValueAux(char *ladd, Int_t atype, TStreamerElement * aElement, Int_t aleng, Int_t *count); @@ -133,7 +144,8 @@ class TStreamerInfo : public TVirtualStreamerInfo { kIgnoreTObjectStreamer = BIT(13), // eventhough BIT(13) is taken up by TObject (to preserverse forward compatibility) kRecovered = BIT(14), kNeedCheck = BIT(15), - kIsCompiled = BIT(16) + kIsCompiled = BIT(16), + kBuildOldUsed = BIT(17) }; enum EReadWrite { diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 2dded853d0d91..c7fe4ec654d7e 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -35,6 +35,8 @@ #include "TStreamerElement.h" #include "TSchemaRuleSet.h" #include "TStreamerInfoActions.h" +#include "TInterpreter.h" +#include "TVirtualMutex.h" #include "TArrayC.h" #if (defined(__linux) || defined(__APPLE__)) && defined(__i386__) && \ @@ -69,6 +71,18 @@ static inline ULong_t Void_Hash(const void *ptr) return TString::Hash(&ptr, sizeof(void*)); } +//______________________________________________________________________________ +static inline bool Class_Has_StreamerInfo(const TClass* cl) +{ + // Thread-safe check on StreamerInfos of a TClass + + // NOTE: we do not need a R__LOCKGUARD2 since we know the + // mutex is available since the TClass constructor will make + // it + R__LOCKGUARD(gCINTMutex); + return cl->GetStreamerInfos()->GetLast()>1; +} + //______________________________________________________________________________ TBufferFile::TBufferFile(TBuffer::EMode mode) :TBuffer(mode), @@ -2744,7 +2758,7 @@ void TBufferFile::SkipVersion(const TClass *cl) // We could have a file created using a Foreign class before // the introduction of the CheckSum. We need to check if ((!cl->IsLoaded() || cl->IsForeign()) && - cl->GetStreamerInfos()->GetLast()>1 ) { + Class_Has_StreamerInfo(cl) ) { const TList *list = ((TFile*)fParent)->GetStreamerInfoCache(); const TStreamerInfo *local = list ? (TStreamerInfo*)list->FindObject(cl->GetName()) : 0; @@ -2848,7 +2862,7 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass // We could have a file created using a Foreign class before // the introduction of the CheckSum. We need to check if ((!cl->IsLoaded() || cl->IsForeign()) && - cl->GetStreamerInfos()->GetLast()>1 ) { + Class_Has_StreamerInfo(cl) ) { const TList *list = ((TFile*)fParent)->GetStreamerInfoCache(); const TStreamerInfo *local = list ? (TStreamerInfo*)list->FindObject(cl->GetName()) : 0; @@ -2959,7 +2973,7 @@ Version_t TBufferFile::ReadVersionForMemberWise(const TClass *cl) // We could have a file created using a Foreign class before // the introduction of the CheckSum. We need to check if ((!cl->IsLoaded() || cl->IsForeign()) && - cl->GetStreamerInfos()->GetLast()>1 ) { + Class_Has_StreamerInfo(cl) ) { const TList *list = ((TFile*)fParent)->GetStreamerInfoCache(); const TStreamerInfo *local = list ? (TStreamerInfo*)list->FindObject(cl->GetName()) : 0; @@ -3609,14 +3623,20 @@ Int_t TBufferFile::ReadClassBuffer(const TClass *cl, void *pointer, Int_t versio // count is the number of bytes for this object in the buffer // - TObjArray *infos = cl->GetStreamerInfos(); - Int_t ninfos = infos->GetSize(); + TObjArray* infos; + Int_t ninfos; + { + R__LOCKGUARD(gCINTMutex); + infos = cl->GetStreamerInfos(); + ninfos = infos->GetSize(); + } if (version < -1 || version >= ninfos) { - Error("ReadBuffer1", "class: %s, attempting to access a wrong version: %d, object skipped at offset %d", - cl->GetName(), version, Length() ); - CheckByteCount(start, count, cl); - return 0; + Error("ReadBuffer1", "class: %s, attempting to access a wrong version: %d, object skipped at offset %d", + cl->GetName(), version, Length() ); + CheckByteCount(start, count, cl); + return 0; } + //--------------------------------------------------------------------------- // The ondisk class has been specified so get foreign streamer info //--------------------------------------------------------------------------- @@ -3636,6 +3656,8 @@ Int_t TBufferFile::ReadClassBuffer(const TClass *cl, void *pointer, Int_t versio //--------------------------------------------------------------------------- else { // The StreamerInfo should exist at this point. + + R__LOCKGUARD(gCINTMutex); sinfo = (TStreamerInfo*)infos->At(version); if (sinfo == 0) { // Unless the data is coming via a socket connection from with schema evolution @@ -3722,6 +3744,7 @@ Int_t TBufferFile::ReadClassBuffer(const TClass *cl, void *pointer, const TClass // Get local streamer info //--------------------------------------------------------------------------- else { + R__LOCKGUARD(gCINTMutex); // The StreamerInfo should exist at this point. TObjArray *infos = cl->GetStreamerInfos(); Int_t infocapacity = infos->Capacity(); @@ -3795,12 +3818,17 @@ Int_t TBufferFile::WriteClassBuffer(const TClass *cl, void *pointer) //build the StreamerInfo if first time for the class TStreamerInfo *sinfo = (TStreamerInfo*)const_cast(cl)->GetCurrentStreamerInfo(); if (sinfo == 0) { - const_cast(cl)->BuildRealData(pointer); - sinfo = new TStreamerInfo(const_cast(cl)); - const_cast(cl)->SetCurrentStreamerInfo(sinfo); - cl->GetStreamerInfos()->AddAtAndExpand(sinfo,cl->GetClassVersion()); - if (gDebug > 0) printf("Creating StreamerInfo for class: %s, version: %d\n",cl->GetName(),cl->GetClassVersion()); - sinfo->Build(); + //Have to be sure between the check and the taking of the lock if the current streamer has changed + R__LOCKGUARD(gCINTMutex); + sinfo = (TStreamerInfo*)const_cast(cl)->GetCurrentStreamerInfo(); + if(sinfo == 0) { + const_cast(cl)->BuildRealData(pointer); + sinfo = new TStreamerInfo(const_cast(cl)); + const_cast(cl)->SetCurrentStreamerInfo(sinfo); + cl->GetStreamerInfos()->AddAtAndExpand(sinfo,cl->GetClassVersion()); + if (gDebug > 0) printf("Creating StreamerInfo for class: %s, version: %d\n",cl->GetName(),cl->GetClassVersion()); + sinfo->Build(); + } } else if (!sinfo->IsCompiled()) { const_cast(cl)->BuildRealData(pointer); sinfo->BuildOld(); diff --git a/io/io/src/TDirectoryFile.cxx b/io/io/src/TDirectoryFile.cxx index 65042c0684510..64e17a24ff96a 100644 --- a/io/io/src/TDirectoryFile.cxx +++ b/io/io/src/TDirectoryFile.cxx @@ -424,6 +424,7 @@ TObject *TDirectoryFile::FindObjectAnyFile(const char *name) const // Scan the memory lists of all files for an object with name TFile *f; + R__LOCKGUARD2(gROOTMutex); TIter next(gROOT->GetListOfFiles()); while ((f = (TFile*)next())) { TObject *obj = f->GetList()->FindObject(name); diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 9df79f0757c8d..6f4880697a51e 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -118,11 +118,18 @@ #include "TSchemaRuleSet.h" #include "TThreadSlots.h" +#if __cplusplus > 199711L +std::atomic TFile::fgBytesRead{0}; +std::atomic TFile::fgBytesWrite{0}; +std::atomic TFile::fgFileCounter{0}; +std::atomic TFile::fgReadCalls{0}; +#else Long64_t TFile::fgBytesRead = 0; Long64_t TFile::fgBytesWrite = 0; Long64_t TFile::fgFileCounter = 0; -Int_t TFile::fgReadaheadSize = 256000; Int_t TFile::fgReadCalls = 0; +#endif +Int_t TFile::fgReadaheadSize = 256000; Bool_t TFile::fgReadInfo = kTRUE; TList *TFile::fgAsyncOpenRequests = 0; TString TFile::fgCacheFileDir; @@ -4534,6 +4541,7 @@ TFile::EAsyncOpenStatus TFile::GetAsyncOpenStatus(const char* name) } // Check also the list of files open + R__LOCKGUARD2(gROOTMutex); TSeqCollection *of = gROOT->GetListOfFiles(); if (of && (of->GetSize() > 0)) { TIter nxf(of); @@ -4580,6 +4588,7 @@ const TUrl *TFile::GetEndpointUrl(const char* name) } // Check also the list of files open + R__LOCKGUARD2(gROOTMutex); TSeqCollection *of = gROOT->GetListOfFiles(); if (of && (of->GetSize() > 0)) { TIter nxf(of); diff --git a/io/io/src/TKey.cxx b/io/io/src/TKey.cxx index 0a86907212d5a..14ab4faea7ea5 100644 --- a/io/io/src/TKey.cxx +++ b/io/io/src/TKey.cxx @@ -46,6 +46,8 @@ // // ////////////////////////////////////////////////////////////////////////// +#include + #include "Riostream.h" #include "TROOT.h" #include "TClass.h" @@ -78,7 +80,7 @@ const ULong64_t kPidOffsetMask = 0xffffffffffffUL; const UChar_t kPidOffsetShift = 48; static TString gTDirectoryString = "TDirectory"; -UInt_t keyAbsNumber = 0; +std::atomic keyAbsNumber{0}; ClassImp(TKey) diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index d90c87142b9d8..01add3f41b944 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -72,8 +72,13 @@ #include "TStreamerInfoActions.h" +#if __cplusplus > 199711L +thread_local TStreamerElement *TStreamerInfo::fgElement = nullptr; +std::atomic TStreamerInfo::fgCount{0}; +#else TStreamerElement *TStreamerInfo::fgElement = 0; Int_t TStreamerInfo::fgCount = 0; +#endif const Int_t kMaxLen = 1024; @@ -209,6 +214,8 @@ void TStreamerInfo::Build() // one by one the list of data members of the analyzed class. R__LOCKGUARD(gCINTMutex); + // Did another thread already do the work? + if (fIsBuilt) return; // This is used to avoid unwanted recursive call to Build fIsBuilt = kTRUE; @@ -504,6 +511,8 @@ void TStreamerInfo::Build() if (!infoalloc) { Error("Build","Could you create a TStreamerInfo for %s\n",TString::Format("%s@@%d",GetName(),GetClassVersion()).Data()); } else { + // Tell clone we should rerun BuildOld + infoalloc->SetBit(kBuildOldUsed,false); infoalloc->BuildCheck(); infoalloc->BuildOld(); TClass *allocClass = infoalloc->GetClass(); @@ -1262,6 +1271,15 @@ namespace { } return kFALSE; } + + //Makes sure kBuildOldUsed set once BuildOld finishes + struct BuildOldGuard { + BuildOldGuard(TStreamerInfo* info): fInfo(info) {} + ~BuildOldGuard() { + fInfo->SetBit(TStreamerInfo::kBuildOldUsed); + } + TStreamerInfo* fInfo; + }; } //______________________________________________________________________________ @@ -1270,6 +1288,8 @@ void TStreamerInfo::BuildOld() // rebuild the TStreamerInfo structure R__LOCKGUARD(gCINTMutex); + if( TestBit(kBuildOldUsed) && !IsOptimized() ) return; + BuildOldGuard buildOldGuard(this); if (gDebug > 0) { printf("\n====>Rebuilding TStreamerInfo for class: %s, version: %d\n", GetName(), fClassVersion); @@ -1942,6 +1962,7 @@ void TStreamerInfo::BuildOld() if (!infoalloc) { Error("BuildOld","Unable to create the StreamerInfo for %s.",TString::Format("%s@@%d",GetName(),GetOnFileClassVersion()).Data()); } else { + infoalloc->SetBit(kBuildOldUsed,false); infoalloc->BuildCheck(); infoalloc->BuildOld(); allocClass = infoalloc->GetClass(); @@ -2070,6 +2091,7 @@ void TStreamerInfo::Clear(Option_t *option) fNdata = 0; fSize = 0; ResetBit(kIsCompiled); + ResetBit(kBuildOldUsed); if (fReadObjectWise) fReadObjectWise->fActions.clear(); if (fReadMemberWise) fReadMemberWise->fActions.clear(); @@ -4315,6 +4337,7 @@ void TStreamerInfo::Streamer(TBuffer &R__b) R__b.ClassEnd(TStreamerInfo::Class()); R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t)); ResetBit(kIsCompiled); + ResetBit(kBuildOldUsed); return; } //====process old versions before automatic schema evolution diff --git a/math/mathcore/inc/TMath.h b/math/mathcore/inc/TMath.h index 2ab7adb5708c9..8fdbf0549eb23 100644 --- a/math/mathcore/inc/TMath.h +++ b/math/mathcore/inc/TMath.h @@ -548,7 +548,7 @@ inline Int_t TMath::IsNaN(Double_t x) { return std::isnan(x); } #endif #else - { return isnan(x); } + { return ::isnan(x); } #endif //--------wrapper to numeric_limits diff --git a/math/smatrix/inc/Math/MatrixInversion.icc b/math/smatrix/inc/Math/MatrixInversion.icc index f344e2fed3ca4..d4d8e9c05d136 100644 --- a/math/smatrix/inc/Math/MatrixInversion.icc +++ b/math/smatrix/inc/Math/MatrixInversion.icc @@ -11,7 +11,10 @@ // inversion algorithms for matrices // taken from CLHEP (L. Moneta May 2006) - +#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#endif namespace ROOT { namespace Math { @@ -670,5 +673,7 @@ int Inverter::DfinvMatrix(MatRepStd & rhs,unsigned int * ir) { } // end namespace Math } // end namespace ROOT - +#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif #endif diff --git a/roofit/roofitcore/src/RooBanner.cxx b/roofit/roofitcore/src/RooBanner.cxx index 89c0338d387ee..67ace14984126 100644 --- a/roofit/roofitcore/src/RooBanner.cxx +++ b/roofit/roofitcore/src/RooBanner.cxx @@ -26,4 +26,4 @@ Int_t doBanner() return 0 ; } -static Int_t dummy = doBanner() ; +//static Int_t dummy = doBanner() ; diff --git a/tree/tree/inc/TBranchSTL.h b/tree/tree/inc/TBranchSTL.h index 13e861c270b8b..4dabe440d3b97 100644 --- a/tree/tree/inc/TBranchSTL.h +++ b/tree/tree/inc/TBranchSTL.h @@ -15,6 +15,9 @@ #include "TBranchObject.h" #include "TBranchElement.h" #include "TIndArray.h" +#if __cplusplus > 199711L +#include +#endif #include #include #include @@ -72,9 +75,17 @@ class TBranchSTL: public TBranch { TIndArray fInd; //! Indices TString fContName; // Class name of referenced object TString fClassName; // Name of the parent class, if we're the data member +#if __cplusplus > 199711L + mutable std::atomic fClassVersion; // Version number of the class +#else mutable Int_t fClassVersion; // Version number of the class +#endif UInt_t fClCheckSum; // Class checksum +#if __cplusplus > 199711L + mutable std::atomic fInfo; //! The streamer info +#else mutable TStreamerInfo *fInfo; //! The streamer info +#endif char* fObject; //! Pointer to object at address or the Int_t fID; // Element serial number in the streamer info }; diff --git a/tree/tree/src/TBranch.cxx b/tree/tree/src/TBranch.cxx index d674054411959..06042163a772c 100644 --- a/tree/tree/src/TBranch.cxx +++ b/tree/tree/src/TBranch.cxx @@ -36,13 +36,14 @@ #include "TTree.h" #include "TTreeCache.h" #include "TTreeCacheUnzip.h" +#include "TVirtualMutex.h" #include "TVirtualPad.h" #include #include #include -R__EXTERN TTree* gTree; +R__EXTERN thread_local TTree* gTree; Int_t TBranch::fgCount = 0; @@ -459,6 +460,7 @@ TBranch::~TBranch() if (fDirectory && (!fTree || fDirectory != fTree->GetDirectory())) { TString bFileName( GetRealFileName() ); + R__LOCKGUARD2(gROOTMutex); TFile* file = (TFile*)gROOT->GetListOfFiles()->FindObject(bFileName); if (file){ file->Close(); @@ -1377,10 +1379,14 @@ TFile* TBranch::GetFile(Int_t mode) if (fDirectory) return fDirectory->GetFile(); // check if a file with this name is in the list of Root files - TFile *file = (TFile*)gROOT->GetListOfFiles()->FindObject(fFileName.Data()); - if (file) { - fDirectory = file; - return file; + TFile *file = 0; + { + R__LOCKGUARD2(gROOTMutex); + file = (TFile*)gROOT->GetListOfFiles()->FindObject(fFileName.Data()); + if (file) { + fDirectory = file; + return file; + } } if (fFileName.Length() == 0) return 0; diff --git a/tree/tree/src/TBranchBrowsable.cxx b/tree/tree/src/TBranchBrowsable.cxx index 12f7b2d8bbea2..eecc9f0651f4b 100644 --- a/tree/tree/src/TBranchBrowsable.cxx +++ b/tree/tree/src/TBranchBrowsable.cxx @@ -27,7 +27,7 @@ #include "TRef.h" #include -R__EXTERN TTree *gTree; +R__EXTERN thread_local TTree *gTree; ClassImp(TVirtualBranchBrowsable); diff --git a/tree/tree/src/TBranchClones.cxx b/tree/tree/src/TBranchClones.cxx index c3a7721f1334c..035caba55ad00 100644 --- a/tree/tree/src/TBranchClones.cxx +++ b/tree/tree/src/TBranchClones.cxx @@ -31,7 +31,7 @@ #include -R__EXTERN TTree* gTree; +R__EXTERN thread_local TTree* gTree; ClassImp(TBranchClones) diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx index 28a655a3506f5..6e8207a631176 100644 --- a/tree/tree/src/TBranchElement.cxx +++ b/tree/tree/src/TBranchElement.cxx @@ -39,6 +39,7 @@ #include "TTree.h" #include "TVirtualCollectionProxy.h" #include "TVirtualCollectionIterators.h" +#include "TVirtualMutex.h" #include "TVirtualPad.h" #include "TBranchSTL.h" #include "TVirtualArray.h" @@ -1946,6 +1947,7 @@ void TBranchElement::InitInfo() // FIXME: Check that the found streamer info checksum matches our branch class checksum here. // Check to see if the class code was unloaded/reloaded // since we were created. + R__LOCKGUARD(gCINTMutex); if (fCheckSum && (cl->IsForeign() || (!cl->IsLoaded() && (fClassVersion == 1) && cl->GetStreamerInfos()->At(1) && (fCheckSum != ((TVirtualStreamerInfo*) cl->GetStreamerInfos()->At(1))->GetCheckSum())))) { // Try to compensate for a class that got unloaded on us. // Search through the streamer infos by checksum @@ -5475,7 +5477,7 @@ Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, cha // independently in the tree. // TStreamerInfo* sinfo = fTree->BuildStreamerInfo(cl); - if (sinfo && splitlevel > 0) { + if (sinfo && splitlevel > 0 && (!sinfo->IsCompiled() || sinfo->IsOptimized()) ) { sinfo->SetBit(TVirtualStreamerInfo::kCannotOptimize); sinfo->Compile(); } diff --git a/tree/tree/src/TBranchSTL.cxx b/tree/tree/src/TBranchSTL.cxx index f2eb83def66ba..40a5247fa7582 100644 --- a/tree/tree/src/TBranchSTL.cxx +++ b/tree/tree/src/TBranchSTL.cxx @@ -17,6 +17,8 @@ #include "TBasket.h" #include "TStreamerInfo.h" #include "TStreamerElement.h" +#include "TInterpreter.h" // For gCINTMutex +#include "TVirtualMutex.h" #include #include @@ -561,6 +563,9 @@ TStreamerInfo* TBranchSTL::GetInfo() const // If the checksum is there and we're dealing with the foreign class //------------------------------------------------------------------------ if( fClCheckSum && cl->IsForeign() ) { + // NOTE: We do not need a R__LOCKGUARD2 since the TClass constructor + // is guaranteed to set the gCINTMutex if it is not already available. + R__LOCKGUARD(gCINTMutex); //--------------------------------------------------------------------- // Loop over the infos //--------------------------------------------------------------------- @@ -579,8 +584,10 @@ TStreamerInfo* TBranchSTL::GetInfo() const } } } - fInfo->SetBit(TVirtualStreamerInfo::kCannotOptimize); - fInfo->BuildOld(); + if((*fInfo).IsOptimized()) { + (*fInfo).SetBit(TVirtualStreamerInfo::kCannotOptimize); + (*fInfo).BuildOld(); + } } return fInfo; } @@ -672,7 +679,7 @@ void TBranchSTL::SetAddress( void* addr ) // Get the appropriate streamer element //------------------------------------------------------------------------ GetInfo(); - TStreamerElement *el = (TStreamerElement*)fInfo->GetElements()->At( fID ); + TStreamerElement *el = (TStreamerElement*)(*fInfo).GetElements()->At( fID ); //------------------------------------------------------------------------ // Set up the addresses diff --git a/tree/tree/src/TFriendElement.cxx b/tree/tree/src/TFriendElement.cxx index 7e05599abfed8..2fc96cbd85fff 100644 --- a/tree/tree/src/TFriendElement.cxx +++ b/tree/tree/src/TFriendElement.cxx @@ -30,7 +30,7 @@ #include "TFile.h" #include "TROOT.h" -R__EXTERN TTree *gTree; +R__EXTERN thread_local TTree *gTree; ClassImp(TFriendElement) diff --git a/tree/tree/src/TLeaf.cxx b/tree/tree/src/TLeaf.cxx index 56fe73735701b..eadaad35e7888 100644 --- a/tree/tree/src/TLeaf.cxx +++ b/tree/tree/src/TLeaf.cxx @@ -24,7 +24,7 @@ #include -R__EXTERN TTree* gTree; +R__EXTERN thread_local TTree* gTree; ClassImp(TLeaf) diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 9cbde8ace55b9..3d5c542ca4fc0 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -376,7 +376,7 @@ Int_t TTree::fgBranchStyle = 1; // Use new TBranch style with TBranchElement. Long64_t TTree::fgMaxTreeSize = 100000000000LL; -TTree* gTree; +thread_local TTree* gTree; ClassImp(TTree) diff --git a/tree/treeplayer/src/TTreeFormula.cxx b/tree/treeplayer/src/TTreeFormula.cxx index 8b59c50405da0..4cf88404e7227 100644 --- a/tree/treeplayer/src/TTreeFormula.cxx +++ b/tree/treeplayer/src/TTreeFormula.cxx @@ -54,7 +54,7 @@ #include const Int_t kMaxLen = 1024; -R__EXTERN TTree *gTree; +R__EXTERN thread_local TTree *gTree; ClassImp(TTreeFormula) diff --git a/tree/treeplayer/src/TTreePlayer.cxx b/tree/treeplayer/src/TTreePlayer.cxx index 83e23aa049c00..0076b20fde491 100644 --- a/tree/treeplayer/src/TTreePlayer.cxx +++ b/tree/treeplayer/src/TTreePlayer.cxx @@ -82,7 +82,7 @@ #include "Math/MinimizerOptions.h" R__EXTERN Foption_t Foption; -R__EXTERN TTree *gTree; +R__EXTERN thread_local TTree *gTree; TVirtualFitter *tFitter=0;