// @(#)root/cont:$Id$ // Author: Rene Brun 28/09/2001 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ ////////////////////////////////////////////////////////////////////////// // // TProcessID // // A TProcessID identifies a ROOT job in a unique way in time and space. // The TProcessID title consists of a TUUID object which provides a globally // unique identifier (for more see TUUID.h). // // A TProcessID is automatically created by the TROOT constructor. // When a TFile contains referenced objects (see TRef), the TProcessID // object is written to the file. // If a file has been written in multiple sessions (same machine or not), // a TProcessID is written for each session. // These objects are used by the class TRef to uniquely identified // any TObject pointed by a TRef. // // When a referenced object is read from a file (its bit kIsReferenced is set), // this object is entered into the objects table of the corresponding TProcessID. // Each TFile has a list of TProcessIDs (see TFile::fProcessIDs) also // accessible via TProcessID::fgPIDs (for all files). // When this object is deleted, it is removed from the table via the cleanup // mechanism invoked by the TObject destructor. // // Each TProcessID has a table (TObjArray *fObjects) that keeps track // of all referenced objects. If a referenced object has a fUniqueID set, // a pointer to this unique object may be found via fObjects->At(fUniqueID). // In the same way, when a TRef::GetObject is called, GetObject uses // its own fUniqueID to find the pointer to the referenced object. // See TProcessID::GetObjectWithID and PutObjectWithID. // // When a referenced object is deleted, its slot in fObjects is set to null. // // See also TProcessUUID: a specialized TProcessID to manage the single list // of TUUIDs. // ////////////////////////////////////////////////////////////////////////// #include "TProcessID.h" #include "TROOT.h" #include "TObjArray.h" #include "TExMap.h" #include "TVirtualMutex.h" #include "TError.h" TObjArray *TProcessID::fgPIDs = 0; //pointer to the list of TProcessID TProcessID *TProcessID::fgPID = 0; //pointer to the TProcessID of the current session UInt_t TProcessID::fgNumber = 0; //Current referenced object instance count TExMap *TProcessID::fgObjPIDs= 0; //Table (pointer,pids) ClassImp(TProcessID) //______________________________________________________________________________ static inline ULong_t Void_Hash(const void *ptr) { // Return hash value for this object. return TString::Hash(&ptr, sizeof(void*)); } //______________________________________________________________________________ TProcessID::TProcessID() { // Default constructor. fCount = 0; fObjects = 0; } //______________________________________________________________________________ TProcessID::~TProcessID() { // Destructor. delete fObjects; fObjects = 0; R__LOCKGUARD2(gROOTMutex); fgPIDs->Remove(this); } //______________________________________________________________________________ TProcessID *TProcessID::AddProcessID() { // Static function to add a new TProcessID to the list of PIDs. R__LOCKGUARD2(gROOTMutex); if (fgPIDs && fgPIDs->GetEntriesFast() >= 65534) { if (fgPIDs->GetEntriesFast() == 65534) { ::Warning("TProcessID::AddProcessID","Maximum number of TProcessID (65535) is almost reached (one left). TRef will stop being functional when the limit is reached."); } else { ::Fatal("TProcessID::AddProcessID","Maximum number of TProcessID (65535) has been reached. TRef are not longer functional."); } } TProcessID *pid = new TProcessID(); if (!fgPIDs) { fgPID = pid; fgPIDs = new TObjArray(10); gROOT->GetListOfCleanups()->Add(fgPIDs); } UShort_t apid = fgPIDs->GetEntriesFast(); pid->IncrementCount(); fgPIDs->Add(pid); // if (apid == 0) for(int incr=0; incr < 65533; ++incr) fgPIDs->Add(0); // NOTE: DEBUGGING ONLY MUST BE REMOVED! char name[20]; snprintf(name,20,"ProcessID%d",apid); pid->SetName(name); pid->SetUniqueID((UInt_t)apid); TUUID u; //apid = fgPIDs->GetEntriesFast(); pid->SetTitle(u.AsString()); return pid; } //______________________________________________________________________________ UInt_t TProcessID::AssignID(TObject *obj) { // static function returning the ID assigned to obj // If the object is not yet referenced, its kIsReferenced bit is set // and its fUniqueID set to the current number of referenced objects so far. R__LOCKGUARD2(gROOTMutex); UInt_t uid = obj->GetUniqueID() & 0xffffff; if (obj == fgPID->GetObjectWithID(uid)) return uid; if (obj->TestBit(kIsReferenced)) { fgPID->PutObjectWithID(obj,uid); return uid; } if (fgNumber >= 16777215) { // This process id is 'full', we need to use a new one. fgPID = AddProcessID(); fgNumber = 0; for(Int_t i = 0; i < fgPIDs->GetLast()+1; ++i) { TProcessID *pid = (TProcessID*)fgPIDs->At(i); if (pid && pid->fObjects && pid->fObjects->GetEntries() == 0) { pid->Clear(); } } } fgNumber++; obj->SetBit(kIsReferenced); uid = fgNumber; // if (fgNumber<10) fgNumber = 16777213; // NOTE: DEBUGGING ONLY MUST BE REMOVED! if ( fgPID->GetUniqueID() < 255 ) { obj->SetUniqueID( (uid & 0xffffff) + (fgPID->GetUniqueID()<<24) ); } else { obj->SetUniqueID( (uid & 0xffffff) + 0xff000000 /* 255 << 24 */ ); } fgPID->PutObjectWithID(obj,uid); return uid; } //______________________________________________________________________________ void TProcessID::CheckInit() { // Initialize fObjects. if (!fObjects) fObjects = new TObjArray(100); } //______________________________________________________________________________ void TProcessID::Cleanup() { // static function (called by TROOT destructor) to delete all TProcessIDs R__LOCKGUARD2(gROOTMutex); fgPIDs->Delete(); gROOT->GetListOfCleanups()->Remove(fgPIDs); delete fgPIDs; fgPIDs = 0; } //______________________________________________________________________________ void TProcessID::Clear(Option_t *) { // delete the TObjArray pointing to referenced objects // this function is called by TFile::Close("R") if (GetUniqueID()>254 && fObjects && fgObjPIDs) { // We might have many references registered in the map for(Int_t i = 0; i < fObjects->GetSize(); ++i) { TObject *obj = fObjects->UncheckedAt(i); if (obj) { ULong64_t hash = Void_Hash(obj); fgObjPIDs->Remove(hash,(Long64_t)obj); (*fObjects)[i] = 0; } } } delete fObjects; fObjects = 0; } //______________________________________________________________________________ Int_t TProcessID::DecrementCount() { // the reference fCount is used to delete the TProcessID // in the TFile destructor when fCount = 0 fCount--; if (fCount < 0) fCount = 0; return fCount; } //______________________________________________________________________________ TProcessID *TProcessID::GetProcessID(UShort_t pid) { // static function returning a pointer to TProcessID number pid in fgPIDs return (TProcessID*)fgPIDs->At(pid); } //______________________________________________________________________________ UInt_t TProcessID::GetNProcessIDs() { // Return the (static) number of process IDs. return fgPIDs ? fgPIDs->GetLast()+1 : 0; } //______________________________________________________________________________ TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, const void *obj) { // static function returning a pointer to TProcessID with its pid // encoded in the highest byte of uid R__LOCKGUARD2(gROOTMutex); Int_t pid = (uid>>24)&0xff; if (pid==0xff) { // Look up the pid in the table (pointer,pid) if (fgObjPIDs==0) return 0; ULong_t hash = Void_Hash(obj); pid = fgObjPIDs->GetValue(hash,(Long_t)obj); } return (TProcessID*)fgPIDs->At(pid); } //______________________________________________________________________________ TProcessID *TProcessID::GetProcessWithUID(const TObject *obj) { // static function returning a pointer to TProcessID with its pid // encoded in the highest byte of obj->GetUniqueID() return GetProcessWithUID(obj->GetUniqueID(),obj); } //______________________________________________________________________________ TProcessID *TProcessID::GetSessionProcessID() { // static function returning the pointer to the session TProcessID return fgPID; } //______________________________________________________________________________ Int_t TProcessID::IncrementCount() { // Increase the reference count to this object. if (!fObjects) fObjects = new TObjArray(100); fCount++; return fCount; } //______________________________________________________________________________ UInt_t TProcessID::GetObjectCount() { // Return the current referenced object count // fgNumber is incremented everytime a new object is referenced return fgNumber; } //______________________________________________________________________________ TObject *TProcessID::GetObjectWithID(UInt_t uidd) { //returns the TObject with unique identifier uid in the table of objects Int_t uid = uidd & 0xffffff; //take only the 24 lower bits if (fObjects==0 || uid >= fObjects->GetSize()) return 0; return fObjects->UncheckedAt(uid); } //______________________________________________________________________________ TProcessID *TProcessID::GetPID() { //static: returns pointer to current TProcessID return fgPID; } //______________________________________________________________________________ TObjArray *TProcessID::GetPIDs() { //static: returns array of TProcessIDs return fgPIDs; } //______________________________________________________________________________ Bool_t TProcessID::IsValid(TProcessID *pid) { // static function. return kTRUE if pid is a valid TProcessID R__LOCKGUARD2(gROOTMutex); if (fgPIDs==0) return kFALSE; if (fgPIDs->IndexOf(pid) >= 0) return kTRUE; if (pid == (TProcessID*)gROOT->GetUUIDs()) return kTRUE; return kFALSE; } //______________________________________________________________________________ void TProcessID::PutObjectWithID(TObject *obj, UInt_t uid) { //stores the object at the uid th slot in the table of objects //The object uniqueid is set as well as its kMustCleanup bit if (uid == 0) uid = obj->GetUniqueID() & 0xffffff; if (!fObjects) fObjects = new TObjArray(100); fObjects->AddAtAndExpand(obj,uid); obj->SetBit(kMustCleanup); if ( (obj->GetUniqueID()&0xff000000)==0xff000000 ) { // We have more than 255 pids we need to store this // pointer in the table(pointer,pid) since there is no // more space in fUniqueID if (fgObjPIDs==0) fgObjPIDs = new TExMap; ULong_t hash = Void_Hash(obj); // We use operator() rather than Add() because // if the address has already been registered, we want to // update it's uniqueID (this can easily happen when the // referenced object have been stored in a TClonesArray. (*fgObjPIDs)(hash, (Long_t)obj) = GetUniqueID(); } } //______________________________________________________________________________ void TProcessID::RecursiveRemove(TObject *obj) { // called by the object destructor // remove reference to obj from the current table if it is referenced if (!fObjects) return; if (!obj->TestBit(kIsReferenced)) return; UInt_t uid = obj->GetUniqueID() & 0xffffff; if (obj == GetObjectWithID(uid)) { if (fgObjPIDs) { ULong64_t hash = Void_Hash(obj); fgObjPIDs->Remove(hash,(Long64_t)obj); } (*fObjects)[uid] = 0; // Avoid recalculation of fLast (compared to ->RemoveAt(uid)) } } //______________________________________________________________________________ void TProcessID::SetObjectCount(UInt_t number) { // static function to set the current referenced object count // fgNumber is incremented everytime a new object is referenced fgNumber = number; }