// @(#)root/cont:$Name: $:$Id: TProcessID.cxx,v 1.30 2006/10/11 10:26:23 rdm Exp $ // 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 "TFile.h" #include "TObjArray.h" #include "TExMap.h" #include "TVirtualMutex.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 TMath::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(const TProcessID &ref) : TNamed(ref) { // TProcessID copy ctor. } //______________________________________________________________________________ TProcessID& TProcessID::operator=(const TProcessID &ref) { // TProcessID assigment operator. if (this!=&ref) { TNamed::operator=(ref); } return *this; } //______________________________________________________________________________ TProcessID *TProcessID::AddProcessID() { // Static function to add a new TProcessID to the list of PIDs. R__LOCKGUARD2(gROOTMutex); 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); char name[20]; sprintf(name,"ProcessID%d",apid); pid->SetName(name); 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; } fgNumber++; obj->SetBit(kIsReferenced); uid = fgNumber; obj->SetUniqueID(uid); fgPID->PutObjectWithID(obj,uid); return uid; } //______________________________________________________________________________ void TProcessID::Cleanup() { // static function (called by TROOT destructor) to delete all TProcessIDs R__LOCKGUARD2(gROOTMutex); fgPIDs->Delete(); gROOT->GetListOfCleanups()->Remove(fgPIDs); delete fgPIDs; } //______________________________________________________________________________ void TProcessID::Clear(Option_t *) { // delete the TObjArray pointing to referenced objects // this function is called by TFile::Close("R") 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); } //______________________________________________________________________________ TProcessID *TProcessID::GetProcessWithUID(UInt_t uid, 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::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); } //______________________________________________________________________________ Bool_t TProcessID::IsValid(TProcessID *pid) { // static function. return kTRUE if pid is a valid TProcessID R__LOCKGUARD2(gROOTMutex); 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 obejct have been stored in a TClonesArray. (*fgObjPIDs)(hash, (Long_t)obj) = GetUniqueID(); } } //______________________________________________________________________________ TProcessID *TProcessID::ReadProcessID(UShort_t pidf, TFile *file) { //The TProcessID with number pidf is read from file. (static function) //If the object is not already entered in the gROOT list, it is added. if (!file) { if (!pidf) return fgPID; //may happen when cloning an object return 0; } TObjArray *pids = file->GetListOfProcessIDs(); TProcessID *pid = 0; if (pidf < pids->GetSize()) pid = (TProcessID *)pids->UncheckedAt(pidf); if (pid) { if (!pid->fObjects) pid->fObjects = new TObjArray(100); return pid; } //check if fProcessIDs[uid] is set in file //if not set, read the process uid from file char pidname[32]; sprintf(pidname,"ProcessID%d",pidf); TDirectory *dirsav = gDirectory; file->cd(); pid = (TProcessID *)file->Get(pidname); if (dirsav) dirsav->cd(); if (gDebug > 0) { printf("ReadProcessID, name=%s, file=%s, pid=%lx\n",pidname,file->GetName(),(Long_t)pid); } if (!pid) { //file->Error("ReadProcessID","Cannot find %s in file %s",pidname,file->GetName()); return 0; } //check that a similar pid is not already registered in fgPIDs TIter next(fgPIDs); TProcessID *p; while ((p = (TProcessID*)next())) { if (!strcmp(p->GetTitle(),pid->GetTitle())) { delete pid; pids->AddAtAndExpand(p,pidf); p->IncrementCount(); return p; } } pids->AddAtAndExpand(pid,pidf); pid->IncrementCount(); fgPIDs->Add(pid); Int_t ind = fgPIDs->IndexOf(pid); pid->SetUniqueID((UInt_t)ind); return pid; } //______________________________________________________________________________ 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)) fObjects->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; } //______________________________________________________________________________ UShort_t TProcessID::WriteProcessID(TProcessID *pidd, TFile *file) { // static function // Check if the ProcessID pid is already in the file. // if not, add it and return the index number in the local file list if (!file) return 0; TProcessID *pid = pidd; if (!pid) pid = fgPID; TObjArray *pids = file->GetListOfProcessIDs(); Int_t npids = file->GetNProcessIDs(); for (Int_t i=0;i<npids;i++) { if (pids->At(i) == pid) return (UShort_t)i; } TDirectory *dirsav = gDirectory; file->cd(); file->SetBit(TFile::kHasReferences); pids->AddAtAndExpand(pid,npids); pid->IncrementCount(); char name[32]; sprintf(name,"ProcessID%d",npids); pid->Write(name); file->IncrementProcessIDs(); if (gDebug > 0) { printf("WriteProcessID, name=%s, file=%s\n",name,file->GetName()); } if (dirsav) dirsav->cd(); return (UShort_t)npids; }