ROOT logo
// @(#)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;
}
 TProcessID.cxx:1
 TProcessID.cxx:2
 TProcessID.cxx:3
 TProcessID.cxx:4
 TProcessID.cxx:5
 TProcessID.cxx:6
 TProcessID.cxx:7
 TProcessID.cxx:8
 TProcessID.cxx:9
 TProcessID.cxx:10
 TProcessID.cxx:11
 TProcessID.cxx:12
 TProcessID.cxx:13
 TProcessID.cxx:14
 TProcessID.cxx:15
 TProcessID.cxx:16
 TProcessID.cxx:17
 TProcessID.cxx:18
 TProcessID.cxx:19
 TProcessID.cxx:20
 TProcessID.cxx:21
 TProcessID.cxx:22
 TProcessID.cxx:23
 TProcessID.cxx:24
 TProcessID.cxx:25
 TProcessID.cxx:26
 TProcessID.cxx:27
 TProcessID.cxx:28
 TProcessID.cxx:29
 TProcessID.cxx:30
 TProcessID.cxx:31
 TProcessID.cxx:32
 TProcessID.cxx:33
 TProcessID.cxx:34
 TProcessID.cxx:35
 TProcessID.cxx:36
 TProcessID.cxx:37
 TProcessID.cxx:38
 TProcessID.cxx:39
 TProcessID.cxx:40
 TProcessID.cxx:41
 TProcessID.cxx:42
 TProcessID.cxx:43
 TProcessID.cxx:44
 TProcessID.cxx:45
 TProcessID.cxx:46
 TProcessID.cxx:47
 TProcessID.cxx:48
 TProcessID.cxx:49
 TProcessID.cxx:50
 TProcessID.cxx:51
 TProcessID.cxx:52
 TProcessID.cxx:53
 TProcessID.cxx:54
 TProcessID.cxx:55
 TProcessID.cxx:56
 TProcessID.cxx:57
 TProcessID.cxx:58
 TProcessID.cxx:59
 TProcessID.cxx:60
 TProcessID.cxx:61
 TProcessID.cxx:62
 TProcessID.cxx:63
 TProcessID.cxx:64
 TProcessID.cxx:65
 TProcessID.cxx:66
 TProcessID.cxx:67
 TProcessID.cxx:68
 TProcessID.cxx:69
 TProcessID.cxx:70
 TProcessID.cxx:71
 TProcessID.cxx:72
 TProcessID.cxx:73
 TProcessID.cxx:74
 TProcessID.cxx:75
 TProcessID.cxx:76
 TProcessID.cxx:77
 TProcessID.cxx:78
 TProcessID.cxx:79
 TProcessID.cxx:80
 TProcessID.cxx:81
 TProcessID.cxx:82
 TProcessID.cxx:83
 TProcessID.cxx:84
 TProcessID.cxx:85
 TProcessID.cxx:86
 TProcessID.cxx:87
 TProcessID.cxx:88
 TProcessID.cxx:89
 TProcessID.cxx:90
 TProcessID.cxx:91
 TProcessID.cxx:92
 TProcessID.cxx:93
 TProcessID.cxx:94
 TProcessID.cxx:95
 TProcessID.cxx:96
 TProcessID.cxx:97
 TProcessID.cxx:98
 TProcessID.cxx:99
 TProcessID.cxx:100
 TProcessID.cxx:101
 TProcessID.cxx:102
 TProcessID.cxx:103
 TProcessID.cxx:104
 TProcessID.cxx:105
 TProcessID.cxx:106
 TProcessID.cxx:107
 TProcessID.cxx:108
 TProcessID.cxx:109
 TProcessID.cxx:110
 TProcessID.cxx:111
 TProcessID.cxx:112
 TProcessID.cxx:113
 TProcessID.cxx:114
 TProcessID.cxx:115
 TProcessID.cxx:116
 TProcessID.cxx:117
 TProcessID.cxx:118
 TProcessID.cxx:119
 TProcessID.cxx:120
 TProcessID.cxx:121
 TProcessID.cxx:122
 TProcessID.cxx:123
 TProcessID.cxx:124
 TProcessID.cxx:125
 TProcessID.cxx:126
 TProcessID.cxx:127
 TProcessID.cxx:128
 TProcessID.cxx:129
 TProcessID.cxx:130
 TProcessID.cxx:131
 TProcessID.cxx:132
 TProcessID.cxx:133
 TProcessID.cxx:134
 TProcessID.cxx:135
 TProcessID.cxx:136
 TProcessID.cxx:137
 TProcessID.cxx:138
 TProcessID.cxx:139
 TProcessID.cxx:140
 TProcessID.cxx:141
 TProcessID.cxx:142
 TProcessID.cxx:143
 TProcessID.cxx:144
 TProcessID.cxx:145
 TProcessID.cxx:146
 TProcessID.cxx:147
 TProcessID.cxx:148
 TProcessID.cxx:149
 TProcessID.cxx:150
 TProcessID.cxx:151
 TProcessID.cxx:152
 TProcessID.cxx:153
 TProcessID.cxx:154
 TProcessID.cxx:155
 TProcessID.cxx:156
 TProcessID.cxx:157
 TProcessID.cxx:158
 TProcessID.cxx:159
 TProcessID.cxx:160
 TProcessID.cxx:161
 TProcessID.cxx:162
 TProcessID.cxx:163
 TProcessID.cxx:164
 TProcessID.cxx:165
 TProcessID.cxx:166
 TProcessID.cxx:167
 TProcessID.cxx:168
 TProcessID.cxx:169
 TProcessID.cxx:170
 TProcessID.cxx:171
 TProcessID.cxx:172
 TProcessID.cxx:173
 TProcessID.cxx:174
 TProcessID.cxx:175
 TProcessID.cxx:176
 TProcessID.cxx:177
 TProcessID.cxx:178
 TProcessID.cxx:179
 TProcessID.cxx:180
 TProcessID.cxx:181
 TProcessID.cxx:182
 TProcessID.cxx:183
 TProcessID.cxx:184
 TProcessID.cxx:185
 TProcessID.cxx:186
 TProcessID.cxx:187
 TProcessID.cxx:188
 TProcessID.cxx:189
 TProcessID.cxx:190
 TProcessID.cxx:191
 TProcessID.cxx:192
 TProcessID.cxx:193
 TProcessID.cxx:194
 TProcessID.cxx:195
 TProcessID.cxx:196
 TProcessID.cxx:197
 TProcessID.cxx:198
 TProcessID.cxx:199
 TProcessID.cxx:200
 TProcessID.cxx:201
 TProcessID.cxx:202
 TProcessID.cxx:203
 TProcessID.cxx:204
 TProcessID.cxx:205
 TProcessID.cxx:206
 TProcessID.cxx:207
 TProcessID.cxx:208
 TProcessID.cxx:209
 TProcessID.cxx:210
 TProcessID.cxx:211
 TProcessID.cxx:212
 TProcessID.cxx:213
 TProcessID.cxx:214
 TProcessID.cxx:215
 TProcessID.cxx:216
 TProcessID.cxx:217
 TProcessID.cxx:218
 TProcessID.cxx:219
 TProcessID.cxx:220
 TProcessID.cxx:221
 TProcessID.cxx:222
 TProcessID.cxx:223
 TProcessID.cxx:224
 TProcessID.cxx:225
 TProcessID.cxx:226
 TProcessID.cxx:227
 TProcessID.cxx:228
 TProcessID.cxx:229
 TProcessID.cxx:230
 TProcessID.cxx:231
 TProcessID.cxx:232
 TProcessID.cxx:233
 TProcessID.cxx:234
 TProcessID.cxx:235
 TProcessID.cxx:236
 TProcessID.cxx:237
 TProcessID.cxx:238
 TProcessID.cxx:239
 TProcessID.cxx:240
 TProcessID.cxx:241
 TProcessID.cxx:242
 TProcessID.cxx:243
 TProcessID.cxx:244
 TProcessID.cxx:245
 TProcessID.cxx:246
 TProcessID.cxx:247
 TProcessID.cxx:248
 TProcessID.cxx:249
 TProcessID.cxx:250
 TProcessID.cxx:251
 TProcessID.cxx:252
 TProcessID.cxx:253
 TProcessID.cxx:254
 TProcessID.cxx:255
 TProcessID.cxx:256
 TProcessID.cxx:257
 TProcessID.cxx:258
 TProcessID.cxx:259
 TProcessID.cxx:260
 TProcessID.cxx:261
 TProcessID.cxx:262
 TProcessID.cxx:263
 TProcessID.cxx:264
 TProcessID.cxx:265
 TProcessID.cxx:266
 TProcessID.cxx:267
 TProcessID.cxx:268
 TProcessID.cxx:269
 TProcessID.cxx:270
 TProcessID.cxx:271
 TProcessID.cxx:272
 TProcessID.cxx:273
 TProcessID.cxx:274
 TProcessID.cxx:275
 TProcessID.cxx:276
 TProcessID.cxx:277
 TProcessID.cxx:278
 TProcessID.cxx:279
 TProcessID.cxx:280
 TProcessID.cxx:281
 TProcessID.cxx:282
 TProcessID.cxx:283
 TProcessID.cxx:284
 TProcessID.cxx:285
 TProcessID.cxx:286
 TProcessID.cxx:287
 TProcessID.cxx:288
 TProcessID.cxx:289
 TProcessID.cxx:290
 TProcessID.cxx:291
 TProcessID.cxx:292
 TProcessID.cxx:293
 TProcessID.cxx:294
 TProcessID.cxx:295
 TProcessID.cxx:296
 TProcessID.cxx:297
 TProcessID.cxx:298
 TProcessID.cxx:299
 TProcessID.cxx:300
 TProcessID.cxx:301
 TProcessID.cxx:302
 TProcessID.cxx:303
 TProcessID.cxx:304
 TProcessID.cxx:305
 TProcessID.cxx:306
 TProcessID.cxx:307
 TProcessID.cxx:308
 TProcessID.cxx:309
 TProcessID.cxx:310
 TProcessID.cxx:311
 TProcessID.cxx:312
 TProcessID.cxx:313
 TProcessID.cxx:314
 TProcessID.cxx:315
 TProcessID.cxx:316
 TProcessID.cxx:317
 TProcessID.cxx:318
 TProcessID.cxx:319
 TProcessID.cxx:320
 TProcessID.cxx:321
 TProcessID.cxx:322
 TProcessID.cxx:323
 TProcessID.cxx:324
 TProcessID.cxx:325
 TProcessID.cxx:326
 TProcessID.cxx:327
 TProcessID.cxx:328
 TProcessID.cxx:329
 TProcessID.cxx:330
 TProcessID.cxx:331
 TProcessID.cxx:332
 TProcessID.cxx:333
 TProcessID.cxx:334
 TProcessID.cxx:335
 TProcessID.cxx:336
 TProcessID.cxx:337
 TProcessID.cxx:338
 TProcessID.cxx:339
 TProcessID.cxx:340
 TProcessID.cxx:341
 TProcessID.cxx:342
 TProcessID.cxx:343
 TProcessID.cxx:344
 TProcessID.cxx:345
 TProcessID.cxx:346
 TProcessID.cxx:347
 TProcessID.cxx:348
 TProcessID.cxx:349
 TProcessID.cxx:350
 TProcessID.cxx:351
 TProcessID.cxx:352
 TProcessID.cxx:353
 TProcessID.cxx:354
 TProcessID.cxx:355
 TProcessID.cxx:356
 TProcessID.cxx:357
 TProcessID.cxx:358
 TProcessID.cxx:359
 TProcessID.cxx:360
 TProcessID.cxx:361
 TProcessID.cxx:362
 TProcessID.cxx:363
 TProcessID.cxx:364
 TProcessID.cxx:365
 TProcessID.cxx:366
 TProcessID.cxx:367
 TProcessID.cxx:368
 TProcessID.cxx:369
 TProcessID.cxx:370
 TProcessID.cxx:371
 TProcessID.cxx:372
 TProcessID.cxx:373
 TProcessID.cxx:374
 TProcessID.cxx:375
 TProcessID.cxx:376
 TProcessID.cxx:377
 TProcessID.cxx:378
 TProcessID.cxx:379
 TProcessID.cxx:380
 TProcessID.cxx:381