TMapFile.cxx

Go to the documentation of this file.
00001 // @(#)root/io:$Id: TMapFile.cxx 34927 2010-08-21 16:14:20Z pcanal $
00002 // Author: Fons Rademakers   08/07/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 #ifdef WIN32
00012 #pragma optimize("",off)
00013 #endif
00014 
00015 //////////////////////////////////////////////////////////////////////////
00016 //                                                                      //
00017 // TMapFile                                                             //
00018 //                                                                      //
00019 // This class implements a shared memory region mapped to a file.       //
00020 // Objects can be placed into this shared memory area using the Add()   //
00021 // member function. To actually place a copy of the object is shared    //
00022 // memory call Update() also whenever the mapped object(s) change(s)    //
00023 // call Update() to put a fresh copy in the shared memory. This extra   //
00024 // step is necessary since it is not possible to share objects with     //
00025 // virtual pointers between processes (the vtbl ptr points to the       //
00026 // originators unique address space and can not be used by the          //
00027 // consumer process(es)). Consumer processes can map the memory region  //
00028 // from this file and access the objects stored in it via the Get()     //
00029 // method (which returns a copy of the object stored in the shared      //
00030 // memory with correct vtbl ptr set). Only objects of classes with a    //
00031 // Streamer() member function defined can be shared.                    //
00032 //                                                                      //
00033 // I know the current implementation is not ideal (you need to copy to  //
00034 // and from the shared memory file) but the main problem is with the    //
00035 // class' virtual_table pointer. This pointer points to a table unique  //
00036 // for every process. Therefore, different options are:                 //
00037 //   1) One could allocate an object directly in shared memory in the   //
00038 //      producer, but the consumer still has to copy the object from    //
00039 //      shared memory into a local object which has the correct vtbl    //
00040 //      pointer for that process (copy ctor's can be used for creating  //
00041 //      the local copy).                                                //
00042 //   2) Another possibility is to only allow objects without virtual    //
00043 //      functions in shared memory (like simple C structs), or to       //
00044 //      forbid (how?) the consumer from calling any virtual functions   //
00045 //      of the objects in shared memory.                                //
00046 //   3) A last option is to copy the object internals to shared memory  //
00047 //      and copy them again from there. This is what is done in the     //
00048 //      TMapFile (using the object Streamer() to make a deep copy).     //
00049 // Option 1) saves one copy, but requires solid copy ctor's (along the  //
00050 // full inheritance chain) to rebuild the object in the consumer. Most  //
00051 // classes don't provide these copy ctor's, especially not when objects //
00052 // contain collections, etc. 2) is too limiting or dangerous (calling   //
00053 // accidentally a virtual function will segv). So since we have a       //
00054 // robust Streamer mechanism I opted for 3).                            //
00055 //                                                                      //
00056 //////////////////////////////////////////////////////////////////////////
00057 
00058 
00059 #ifdef WIN32
00060 #  include <windows.h>
00061 #  include <process.h>
00062 #  ifdef GetObject
00063 #    undef GetObject
00064 #  endif
00065 #  define HAVE_SEMOP
00066 
00067 # ifdef CreateSemaphore
00068 #   undef CreateSemaphore
00069 # endif
00070 
00071 # ifdef AcquireSemaphore
00072 #   undef AcquireSemaphore;
00073 # endif
00074 
00075 # ifdef ReleaseSemaphore
00076 #   undef ReleaseSemaphore
00077 # endif
00078 
00079 # ifdef DeleteSemaphore
00080 #   undef DeleteSemaphore
00081 # endif
00082 
00083 #else
00084 #  define INVALID_HANDLE_VALUE -1
00085 #endif
00086 
00087 #include <fcntl.h>
00088 #include <errno.h>
00089 
00090 #include "TMapFile.h"
00091 #include "TKeyMapFile.h"
00092 #include "TDirectoryFile.h"
00093 #include "TBrowser.h"
00094 #include "TString.h"
00095 #include "TSystem.h"
00096 #include "TClass.h"
00097 #include "TBufferFile.h"
00098 #include "TVirtualMutex.h"
00099 #include <cmath>
00100 
00101 #if defined(R__UNIX) && !defined(R__MACOSX) && !defined(R__WINGCC)
00102 #define HAVE_SEMOP
00103 #include <sys/types.h>
00104 #include <sys/ipc.h>
00105 #include <sys/sem.h>
00106 #if defined(R__HPUX) || (defined (R__ALPHA) && !defined(R__FBSD)) || \
00107     defined (R__SOLARIS) || defined(R__AIX) || defined(R__HIUX) || \
00108     __GLIBC_MINOR__ > 0
00109 union semun {
00110    int val;                      // value for SETVAL
00111    struct semid_ds *buf;         // buffer for IPC_STAT & IPC_SET
00112    ushort *array;                // array for GETALL & SETALL
00113 };
00114 #endif
00115 #if defined(R__LINUX) || defined(R__LYNXOS) || defined(R__HURD)
00116 #  define       SEM_A   0200     // alter permission
00117 #  define       SEM_R   0400     // read permission
00118 #endif
00119 #endif
00120 
00121 
00122 Long_t TMapFile::fgMapAddress = 0;
00123 void  *TMapFile::fgMmallocDesc = 0;
00124 
00125 //void *gMmallocDesc = 0; //is initialized in TClass.cxx
00126 
00127 
00128 
00129 //______________________________________________________________________________
00130 TMapRec::TMapRec(const char *name, const TObject *obj, Int_t size, void *buf)
00131 {
00132    /// Constructor.
00133    fName      = StrDup(name);
00134    fClassName = 0;
00135    fObject    = (TObject*)obj;
00136    fBuffer    = buf;
00137    fBufSize   = size;
00138    fNext      = 0;
00139 }
00140 
00141 //______________________________________________________________________________
00142 TMapRec::~TMapRec()
00143 {
00144    // Destructor.
00145    delete [] fName;
00146    delete [] fClassName;
00147 }
00148 
00149 //______________________________________________________________________________
00150 TObject *TMapRec::GetObject() const
00151 {
00152    // This method returns a pointer to the original object. NOTE: this pointer
00153    // is only valid in the process that produces the shared memory file. In a
00154    // consumer process this pointer is illegal! Be careful.
00155 
00156    return fObject;
00157 }
00158 
00159 
00160 
00161 
00162 ClassImp(TMapFile)
00163 
00164 //______________________________________________________________________________
00165 TMapFile::TMapFile()
00166 {
00167    // Default ctor. Does not much except setting some basic values.
00168 
00169    fFd          = -1;
00170    fVersion     = 0;
00171    fName        = 0;
00172    fTitle       = 0;
00173    fOption      = 0;
00174    fMmallocDesc = 0;
00175    fBaseAddr    = 0;
00176    fSize        = 0;
00177    fFirst       = 0;
00178    fLast        = 0;
00179    fOffset      = 0;
00180    fDirectory   = 0;
00181    fBrowseList  = 0;
00182    fWritable    = kFALSE;
00183    fSemaphore   = -1;
00184    fhSemaphore  = 0;
00185    fGetting     = 0;
00186    fWritten     = 0;
00187    fSumBuffer   = 0;
00188    fSum2Buffer  = 0;
00189 }
00190 
00191 //______________________________________________________________________________
00192 TMapFile::TMapFile(const char *name, const char *title, Option_t *option,
00193                    Int_t size, TMapFile *&newMapFile)
00194 {
00195    // Create a memory mapped file. This opens a file (to which the
00196    // memory will be mapped) and attaches a memory region to it.
00197    // Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE" or
00198    // "READ" (see TFile). The default open mode is "READ". The size
00199    // argument specifies the maximum size of shared memory file in bytes.
00200    // This protected ctor is called via the static Create() method.
00201 
00202 #ifndef WIN32
00203    fFd          = -1;
00204    fSemaphore   = -1;
00205    fhSemaphore  = 0;
00206 #else
00207    fFd          = (Int_t) INVALID_HANDLE_VALUE;
00208    fSemaphore   = (Int_t) INVALID_HANDLE_VALUE;
00209 #endif
00210    fMmallocDesc = 0;
00211    fSize        = size;
00212    fFirst       = 0;
00213    fOffset      = 0;
00214    fVersion     = gROOT->GetVersionInt();
00215    fTitle       = StrDup(title);
00216    fOption      = StrDup(option);
00217    fDirectory   = 0;
00218    fBrowseList  = 0;
00219    fGetting     = 0;
00220    fWritten     = 0;
00221    fSumBuffer   = 0;
00222    fSum2Buffer  = 0;
00223 
00224    char  *cleanup = 0;
00225    Bool_t create  = kFALSE;
00226    Bool_t recreate, update, read;
00227 
00228    {
00229       TString opt = option;
00230 
00231       if (!opt.CompareTo("NEW", TString::kIgnoreCase) ||
00232           !opt.CompareTo("CREATE", TString::kIgnoreCase))
00233          create = kTRUE;
00234       recreate = opt.CompareTo("RECREATE", TString::kIgnoreCase)
00235                  ? kFALSE : kTRUE;
00236       update   = opt.CompareTo("UPDATE", TString::kIgnoreCase)
00237                  ? kFALSE : kTRUE;
00238       read     = opt.CompareTo("READ", TString::kIgnoreCase)
00239                  ? kFALSE : kTRUE;
00240       if (!create && !recreate && !update && !read) {
00241          read    = kTRUE;
00242          delete [] fOption;
00243          fOption = StrDup("READ");
00244       }
00245    }
00246 
00247    const char *fname;
00248    if ((fname = gSystem->ExpandPathName(name))) {
00249       fName = StrDup(fname);
00250       delete [] (char*)fname;
00251       fname = fName;
00252    } else {
00253       Error("TMapFile", "error expanding path %s", fname);
00254       goto zombie;
00255    }
00256 
00257    if (recreate) {
00258       if (!gSystem->AccessPathName(fname, kFileExists))
00259          gSystem->Unlink(fname);
00260       recreate = kFALSE;
00261       create   = kTRUE;
00262       delete [] fOption;
00263       fOption  = StrDup("CREATE");
00264    }
00265    if (create && !gSystem->AccessPathName(fname, kFileExists)) {
00266       Error("TMapFile", "file %s already exists", fname);
00267       goto zombie;
00268    }
00269    if (update) {
00270       if (gSystem->AccessPathName(fname, kFileExists)) {
00271          update = kFALSE;
00272          create = kTRUE;
00273       }
00274       if (update && gSystem->AccessPathName(fname, kWritePermission)) {
00275          Error("TMapFile", "no write permission, could not open file %s", fname);
00276          goto zombie;
00277       }
00278    }
00279    if (read) {
00280       if (gSystem->AccessPathName(fname, kFileExists)) {
00281          Error("TMapFile", "file %s does not exist", fname);
00282          goto zombie;
00283       }
00284       if (gSystem->AccessPathName(fname, kReadPermission)) {
00285          Error("TMapFile", "no read permission, could not open file %s", fname);
00286          goto zombie;
00287       }
00288    }
00289 
00290    // Open file to which memory will be mapped
00291    if (create || update) {
00292 #ifndef WIN32
00293       fFd = open(fname, O_RDWR | O_CREAT, 0644);
00294 #else
00295       fFd = (Int_t) CreateFile(fname,                    // pointer to name of the file
00296                      GENERIC_WRITE | GENERIC_READ,       // access (read-write) mode
00297                      FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
00298                      NULL,                               // pointer to security attributes
00299                      OPEN_ALWAYS,                        // how to create
00300                      FILE_ATTRIBUTE_TEMPORARY,           // file attributes
00301                      (HANDLE) NULL);                     // handle to file with attributes to copy
00302 #endif
00303       if (fFd == (Int_t)INVALID_HANDLE_VALUE) {
00304          SysError("TMapFile", "file %s can not be opened", fname);
00305          goto zombie;
00306       }
00307       fWritable = kTRUE;
00308    } else {
00309 #ifndef WIN32
00310       fFd = open(fname, O_RDONLY);
00311 #else
00312       fFd = (Int_t) CreateFile(fname,                    // pointer to name of the file
00313                      GENERIC_READ,                       // access (read-write) mode
00314                      FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
00315                      NULL,                               // pointer to security attributes
00316                      OPEN_EXISTING,                      // how to create
00317                      FILE_ATTRIBUTE_TEMPORARY,           // file attributes
00318                      (HANDLE) NULL);                     // handle to file with attributes to copy
00319 #endif
00320       if (fFd == (Int_t)INVALID_HANDLE_VALUE) {
00321          SysError("TMapFile", "file %s can not be opened for reading", fname);
00322          goto zombie;
00323       }
00324       fWritable = kFALSE;
00325    }
00326 
00327    // Attach memory region to file.
00328    void *mapto;
00329    TMapFile *mapfil;
00330 
00331    if (((mapto = MapToAddress()) == (void *)-1) ||
00332 #ifndef WIN32
00333        ((fMmallocDesc = mmalloc_attach(fFd, mapto, fSize)) == 0)) {
00334 #else
00335        ((fMmallocDesc = mmalloc_attach((HANDLE) fFd, mapto, fSize)) == 0)) {
00336 #endif
00337 
00338       if (mapto == (void *)-1) {
00339          Error("TMapFile", "no memory mapped file capability available\n"
00340                            "Use rootn.exe or link application against \"-lNew\"");
00341       } else {
00342          if (fMmallocDesc == 0 && fWritable)
00343             Error("TMapFile", "mapped file not in mmalloc format or\n"
00344                               "already open in RW mode by another process");
00345          if (fMmallocDesc == 0 && !fWritable)
00346             Error("TMapFile", "mapped file not in mmalloc format");
00347       }
00348 #ifndef WIN32
00349       close(fFd);
00350 #else
00351       CloseHandle((HANDLE) fFd);
00352 #endif
00353       fFd = -1;
00354       if (create)
00355          gSystem->Unlink(fname);
00356       goto zombie;
00357 
00358    } else if ((mapfil = (TMapFile *) mmalloc_getkey(fMmallocDesc, 0)) != 0) {
00359 
00360       // File contains mmalloc heap. If we are in write mode and mapped
00361       // file already connected in write mode switch to read-only mode.
00362       // Check if ROOT versions are compatible.
00363       // If so update mapped version of TMapFile to reflect current
00364       // situation (only if not opened in READ mode).
00365       if (mapfil->fVersion != fVersion) {
00366          Error("TMapFile", "map file %s (%d) incompatible with current ROOT version (%d)",
00367                fname, mapfil->fVersion, fVersion);
00368          mmalloc_detach(fMmallocDesc);
00369 #ifndef WIN32
00370          close(fFd);
00371 #else
00372          CloseHandle((HANDLE) fFd);
00373 #endif
00374          fFd = -1;
00375          fMmallocDesc = 0;
00376          goto zombie;
00377       }
00378 
00379       if (mapfil->fWritable && fWritable) {
00380          Warning("TMapFile", "map file already open in write mode, opening in read-only mode");
00381          fWritable = kFALSE;
00382       }
00383 
00384       fBaseAddr = mapfil->fBaseAddr;
00385       fSize     = mapfil->fSize;
00386 
00387       if (fWritable) {
00388          // create new TMapFile object in mapped heap to get correct vtbl ptr
00389          CreateSemaphore();
00390          gMmallocDesc = fMmallocDesc;
00391          TMapFile *mf = new TMapFile(*mapfil);
00392          mf->fFd        = fFd;
00393          mf->fWritable  = kTRUE;
00394          cleanup        = mf->fOption;
00395          mf->fOption    = StrDup(fOption);
00396          mf->fSemaphore = fSemaphore;
00397 #ifdef WIN32
00398          mf->CreateSemaphore(fSemaphore);
00399 #endif
00400          mmalloc_setkey(fMmallocDesc, 0, mf);
00401          gMmallocDesc = 0;
00402          mapfil = mf;
00403       } else {
00404          gMmallocDesc = 0;    // make sure we are in sbrk heap
00405          fOffset      = ((struct mdesc *) fMmallocDesc)->offset;
00406          TMapFile *mf = new TMapFile(*mapfil, fOffset);
00407          delete [] mf->fOption;
00408          mf->fFd          = fFd;
00409          mf->fOption      = StrDup("READ");
00410          mf->fMmallocDesc = fMmallocDesc;
00411          mf->fWritable    = kFALSE;
00412          mapfil = mf;
00413       }
00414 
00415       // store shadow mapfile (it contains the real fFd in case map
00416       // is not writable)
00417       fVersion  = -1;   // make this the shadow map file
00418       R__LOCKGUARD2(gROOTMutex);
00419       gROOT->GetListOfMappedFiles()->AddLast(this);
00420 
00421    } else {
00422 
00423       // New file. If the file is writable create a new copy of the
00424       // TMapFile which will now be allocated on the memory mapped heap.
00425       if (!fWritable) {
00426          Error("TMapFile", "map file is not writable");
00427          mmalloc_detach(fMmallocDesc);
00428 #ifndef WIN32
00429          close(fFd);
00430 #else
00431          CloseHandle((HANDLE) fFd);
00432 #endif
00433          fFd = -1;
00434          fMmallocDesc = 0;
00435          goto zombie;
00436       }
00437 
00438       fBaseAddr = (ULong_t)((struct mdesc *) fMmallocDesc)->base;
00439 
00440       CreateSemaphore();
00441 
00442       gMmallocDesc = fMmallocDesc;
00443 
00444       mapfil = new TMapFile(*this);
00445       mmalloc_setkey(fMmallocDesc, 0, mapfil);
00446 
00447       gMmallocDesc = 0;
00448 
00449       // store shadow mapfile
00450       fVersion  = -1;   // make this the shadow map file
00451       R__LOCKGUARD2(gROOTMutex);
00452       gROOT->GetListOfMappedFiles()->AddLast(this);
00453 
00454    }
00455 
00456    mapfil->InitDirectory();
00457    {
00458       R__LOCKGUARD2(gROOTMutex);
00459       gROOT->GetListOfMappedFiles()->AddFirst(mapfil);
00460    }
00461 
00462    if (cleanup) delete [] cleanup;
00463 
00464    newMapFile = mapfil;
00465 
00466    return;
00467 
00468 zombie:
00469    // error in file opening occured, make this object a zombie
00470    MakeZombie();
00471    newMapFile   = this;
00472    gMmallocDesc = 0;
00473 }
00474 
00475 //______________________________________________________________________________
00476 TMapFile::TMapFile(const TMapFile &f, Long_t offset) : TObject(f)
00477 {
00478    // Private copy ctor. Used by the the ctor to create a new version
00479    // of TMapFile in the memory mapped heap. It's main purpose is to
00480    // correctly create the string data members.
00481 
00482    fFd          = f.fFd;
00483    fVersion     = f.fVersion;
00484    fName        = StrDup((char *)((long)f.fName + offset));
00485    fTitle       = StrDup((char *)((long)f.fTitle + offset));
00486    fOption      = StrDup((char *)((long)f.fOption + offset));
00487    fMmallocDesc = f.fMmallocDesc;
00488    fBaseAddr    = f.fBaseAddr;
00489    fSize        = f.fSize;
00490    fFirst       = f.fFirst;
00491    fLast        = f.fLast;
00492    fWritable    = f.fWritable;
00493    fSemaphore   = f.fSemaphore;
00494    fOffset      = offset;
00495    fDirectory   = 0;
00496    fBrowseList  = 0;
00497    fGetting     = 0;
00498    fWritten     = f.fWritten;
00499    fSumBuffer   = f.fSumBuffer;
00500    fSum2Buffer  = f.fSum2Buffer;
00501 #ifdef WIN32
00502    CreateSemaphore(fSemaphore);
00503 #else
00504    fhSemaphore = f.fhSemaphore;
00505 #endif
00506 }
00507 
00508 //______________________________________________________________________________
00509 TMapFile::~TMapFile()
00510 {
00511    // TMapFiles may not be deleted, since we want to keep the complete
00512    // TMapFile object in the mapped file for later re-use. To enforce this
00513    // the delete operator has been made private. Use Close() to properly
00514    // terminate a TMapFile (also done via the TROOT dtor).
00515 
00516    if (fDirectory == gDirectory) gDirectory = gROOT;
00517    delete fDirectory; fDirectory = 0;
00518    if (fBrowseList) fBrowseList->Delete();
00519    delete fBrowseList; fBrowseList = 0;
00520 
00521    // if shadow map file we are done here
00522    if (fVersion == -1)
00523       return;
00524 
00525    // Writable mapfile is allocated in mapped memory. This object should
00526    // not be deleted by ::operator delete(), because it is needed if we
00527    // want to connect later to the file again.
00528    if (fWritable)
00529       TObject::SetDtorOnly(this);
00530 
00531    Close("dtor");
00532 
00533    fgMmallocDesc = fMmallocDesc;
00534 }
00535 
00536 //______________________________________________________________________________
00537 void TMapFile::InitDirectory()
00538 {
00539    // Create the directory associated to this mapfile
00540 
00541    gDirectory = 0;
00542    fDirectory = new TDirectoryFile();
00543    fDirectory->SetName(GetName());
00544    fDirectory->SetTitle(GetTitle());
00545    fDirectory->Build();
00546    fDirectory->SetMother(this);
00547    gDirectory = fDirectory;
00548 }
00549 
00550 //______________________________________________________________________________
00551 void TMapFile::Add(const TObject *obj, const char *name)
00552 {
00553    // Add an object to the list of objects to be stored in shared memory.
00554    // To place the object actually into shared memory call Update().
00555 
00556    if (!fWritable || !fMmallocDesc) return;
00557 
00558    Bool_t lock = fGetting != obj ? kTRUE : kFALSE;
00559 
00560    if (lock)
00561       AcquireSemaphore();
00562 
00563    gMmallocDesc = fMmallocDesc;
00564 
00565    const char *n;
00566    if (name && *name)
00567       n = name;
00568    else
00569       n = obj->GetName();
00570 
00571    if (Remove(n, kFALSE)) {
00572       //Warning("Add", "replaced object with same name %s", n);
00573    }
00574 
00575    TMapRec *mr = new TMapRec(n, obj, 0, 0);
00576    if (!fFirst) {
00577       fFirst = mr;
00578       fLast  = mr;
00579    } else {
00580       fLast->fNext = mr;
00581       fLast        = mr;
00582    }
00583 
00584    gMmallocDesc = 0;
00585 
00586    if (lock)
00587       ReleaseSemaphore();
00588 }
00589 
00590 //______________________________________________________________________________
00591 void TMapFile::Update(TObject *obj)
00592 {
00593    // Update an object (or all objects, if obj == 0) in shared memory.
00594 
00595    if (!fWritable || !fMmallocDesc) return;
00596 
00597    AcquireSemaphore();
00598 
00599    gMmallocDesc = fMmallocDesc;
00600 
00601    Bool_t all = (obj == 0) ? kTRUE : kFALSE;
00602 
00603    TMapRec *mr = fFirst;
00604    while (mr) {
00605       if (all || mr->fObject == obj) {
00606          TBufferFile *b;
00607          if (!mr->fBufSize) {
00608             b = new TBufferFile(TBuffer::kWrite, GetBestBuffer());
00609             mr->fClassName = StrDup(mr->fObject->ClassName());
00610          } else
00611             b = new TBufferFile(TBuffer::kWrite, mr->fBufSize, mr->fBuffer);
00612          b->MapObject(mr->fObject);  //register obj in map to handle self reference
00613          mr->fObject->Streamer(*b);
00614          mr->fBufSize = b->BufferSize();
00615          mr->fBuffer  = b->Buffer();
00616          SumBuffer(b->Length());
00617          b->DetachBuffer();
00618          delete b;
00619       }
00620       mr = mr->fNext;
00621    }
00622 
00623    gMmallocDesc = 0;
00624 
00625    ReleaseSemaphore();
00626 }
00627 
00628 //______________________________________________________________________________
00629 TObject *TMapFile::Remove(TObject *obj, Bool_t lock)
00630 {
00631    // Remove object from shared memory. Returns pointer to removed
00632    // object if successful, 0 otherwise.
00633 
00634    if (!fWritable || !fMmallocDesc) return 0;
00635 
00636    if (lock)
00637       AcquireSemaphore();
00638 
00639    TObject *retObj = 0;
00640    TMapRec *prev = 0, *mr = fFirst;
00641    while (mr) {
00642       if (mr->fObject == obj) {
00643          if (mr == fFirst) {
00644             fFirst = mr->fNext;
00645             if (mr == fLast)
00646                fLast = 0;
00647          } else {
00648             prev->fNext = mr->fNext;
00649             if (mr == fLast)
00650                fLast = prev;
00651          }
00652          retObj = obj;
00653          delete mr;
00654          break;
00655       }
00656       prev = mr;
00657       mr   = mr->fNext;
00658    }
00659 
00660    if (lock)
00661       ReleaseSemaphore();
00662 
00663    return retObj;
00664 }
00665 
00666 //______________________________________________________________________________
00667 TObject *TMapFile::Remove(const char *name, Bool_t lock)
00668 {
00669    // Remove object by name from shared memory. Returns pointer to removed
00670    // object if successful, 0 otherwise.
00671 
00672    if (!fWritable || !fMmallocDesc) return 0;
00673 
00674    if (lock)
00675       AcquireSemaphore();
00676 
00677    TObject *retObj = 0;
00678    TMapRec *prev = 0, *mr = fFirst;
00679    while (mr) {
00680       if (!strcmp(mr->fName, name)) {
00681          if (mr == fFirst) {
00682             fFirst = mr->fNext;
00683             if (mr == fLast)
00684                fLast = 0;
00685          } else {
00686             prev->fNext = mr->fNext;
00687             if (mr == fLast)
00688                fLast = prev;
00689          }
00690          retObj = mr->fObject;
00691          delete mr;
00692          break;
00693       }
00694       prev = mr;
00695       mr   = mr->fNext;
00696    }
00697 
00698    if (lock)
00699       ReleaseSemaphore();
00700 
00701    return retObj;
00702 }
00703 
00704 //______________________________________________________________________________
00705 void TMapFile::RemoveAll()
00706 {
00707    // Remove all objects from shared memory.
00708 
00709    if (!fWritable || !fMmallocDesc) return;
00710 
00711    AcquireSemaphore();
00712 
00713    TMapRec *mr = fFirst;
00714    while (mr) {
00715       TMapRec *t = mr;
00716       mr = mr->fNext;
00717       delete t;
00718    }
00719    fFirst = fLast = 0;
00720 
00721    ReleaseSemaphore();
00722 }
00723 
00724 //______________________________________________________________________________
00725 TObject *TMapFile::Get(const char *name, TObject *delObj)
00726 {
00727    // Return pointer to object retrieved from shared memory. The object must
00728    // be deleted after use. If delObj is a pointer to a previously allocated
00729    // object it will be deleted. Returns 0 in case object with the given
00730    // name does not exist.
00731 
00732    if (!fMmallocDesc) return 0;
00733 
00734    AcquireSemaphore();
00735 
00736    delete delObj;
00737 
00738    TObject *obj = 0;
00739    TMapRec *mr = GetFirst();
00740    while (OrgAddress(mr)) {
00741       if (!strcmp(mr->GetName(fOffset), name)) {
00742          if (!mr->fBufSize) goto release;
00743          TClass *cl = TClass::GetClass(mr->GetClassName(fOffset));
00744          if (!cl) {
00745             Error("Get", "unknown class %s", mr->GetClassName(fOffset));
00746             goto release;
00747          }
00748 
00749          obj = (TObject *)cl->New();
00750          if (!obj) {
00751             Error("Get", "cannot create new object of class %s", mr->GetClassName(fOffset));
00752             goto release;
00753          }
00754 
00755          fGetting = obj;
00756          TBufferFile *b = new TBufferFile(TBuffer::kRead, mr->fBufSize, mr->GetBuffer(fOffset));
00757          b->MapObject(obj);  //register obj in map to handle self reference
00758          obj->Streamer(*b);
00759          b->DetachBuffer();
00760          delete b;
00761          fGetting = 0;
00762          goto release;
00763       }
00764       mr = mr->GetNext(fOffset);
00765    }
00766 
00767 release:
00768    ReleaseSemaphore();
00769 
00770    return obj;
00771 }
00772 
00773 //______________________________________________________________________________
00774 #ifndef WIN32
00775 void TMapFile::CreateSemaphore(int)
00776 #else
00777 void TMapFile::CreateSemaphore(int pid)
00778 #endif
00779 {
00780    // Create semaphore used for synchronizing access to shared memory.
00781 
00782 #ifdef HAVE_SEMOP
00783 #ifndef WIN32
00784    // create semaphore to synchronize access (should use read/write lock)
00785    fSemaphore = semget(IPC_PRIVATE, 1, SEM_R|SEM_A|(SEM_R>>3)|(SEM_A>>3)|
00786                                        (SEM_R>>6)|(SEM_A>>6));
00787 
00788    // set semaphore to 1
00789    if (fSemaphore != -1) {
00790       union semun set;
00791       set.val = 1;
00792       semctl(fSemaphore, 0, SETVAL, set);
00793    }
00794 #else
00795    char buffer[] ="ROOT_Semaphore_xxxxxxxx";
00796    int lbuf = strlen(buffer);
00797    if (!pid) fSemaphore = getpid();
00798    fhSemaphore = (ULong_t)CreateMutex(NULL,FALSE,itoa(fSemaphore,&buffer[lbuf-8],16));
00799    if (fhSemaphore == 0) fSemaphore = (Int_t)INVALID_HANDLE_VALUE;
00800 #endif
00801 #endif
00802 }
00803 
00804 //______________________________________________________________________________
00805 void TMapFile::DeleteSemaphore()
00806 {
00807    // Delete the semaphore.
00808 
00809 #ifdef HAVE_SEMOP
00810    // remove semaphore
00811 #ifndef WIN32
00812    if (fSemaphore != -1) {
00813       int semid  = fSemaphore;
00814       fSemaphore = -1;
00815       union semun set;
00816       set.val = 0;
00817       semctl(semid, 0, IPC_RMID, set);
00818    }
00819 #else
00820    if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE) {
00821       CloseHandle((HANDLE)fhSemaphore);
00822       fhSemaphore = 0;
00823       fSemaphore  = (Int_t)INVALID_HANDLE_VALUE;
00824    }
00825 #endif
00826 #endif
00827 }
00828 
00829 //______________________________________________________________________________
00830 Int_t TMapFile::AcquireSemaphore()
00831 {
00832    // Acquire semaphore. Returns 0 if OK, -1 on error.
00833 
00834 #ifdef HAVE_SEMOP
00835 #ifndef WIN32
00836    if (fSemaphore != -1) {
00837       struct sembuf buf = { 0, -1, SEM_UNDO };
00838       int intr = 0;
00839 again:
00840       if (semop(fSemaphore, &buf, 1) == -1) {
00841 #if defined(R__FBSD) || defined(R__OBSD)
00842          if (TSystem::GetErrno() == EINVAL)
00843 #else
00844          if (TSystem::GetErrno() == EIDRM)
00845 #endif
00846             fSemaphore = -1;
00847 #if !defined(R__FBSD)
00848          if (TSystem::GetErrno() == EINTR) {
00849             if (intr > 2)
00850                return -1;
00851             TSystem::ResetErrno();
00852             intr++;
00853             goto again;
00854          }
00855 #endif
00856       }
00857    }
00858 #else
00859    // Enter Critical section to "write" lock
00860    if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE)
00861       WaitForSingleObject((HANDLE)fhSemaphore,INFINITE);
00862 #endif
00863 #endif
00864 
00865    // file might have grown, update mapping on reader to new size
00866    if (!fWritable && fMmallocDesc) {
00867       if (mmalloc_update_mapping(fMmallocDesc) == -1)
00868          Error("AcquireSemaphore", "cannot update mapping");
00869    }
00870 
00871    return 0;
00872 }
00873 
00874 //______________________________________________________________________________
00875 Int_t TMapFile::ReleaseSemaphore()
00876 {
00877    // Release semaphore. Returns 0 if OK, -1 on error.
00878 
00879 #ifdef HAVE_SEMOP
00880 #ifndef WIN32
00881    if (fSemaphore != -1) {
00882       struct sembuf buf = { 0, 1, SEM_UNDO };
00883       if (semop(fSemaphore, &buf, 1) == -1) {
00884 #if defined(R__FBSD) || defined(R__OBSD)
00885          if (TSystem::GetErrno() == EINVAL)
00886 #else
00887          if (TSystem::GetErrno() == EIDRM)
00888 #endif
00889             fSemaphore = -1;
00890       }
00891    }
00892 #else
00893    if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE)
00894       ReleaseMutex((HANDLE)fhSemaphore);
00895 #endif
00896 #endif
00897    return 0;
00898 }
00899 
00900 //______________________________________________________________________________
00901 void TMapFile::Close(Option_t *option)
00902 {
00903    // Close a mapped file. First detach mapped memory then close file.
00904    // No member functions of a TMapFile that was opened in write mode
00905    // may be called after Close() (this includes, of course, "delete" which
00906    // would call the dtors). The option="dtor" is only used when called
00907    // via the ~TMapFile.
00908 
00909    if (!fMmallocDesc) return;
00910 
00911    TMapFile *shadow = FindShadowMapFile();
00912    if (!shadow) {
00913       Error("Close", "shadow map == 0, should never happen!");
00914       return;
00915    }
00916 
00917    {
00918       R__LOCKGUARD2(gROOTMutex);
00919       gROOT->GetListOfMappedFiles()->Remove(shadow);
00920       gROOT->GetListOfMappedFiles()->Remove(this);
00921    }
00922 
00923    if (shadow->fWritable) {
00924       fWritable = kFALSE;
00925       DeleteSemaphore();
00926    }
00927 
00928    if (fMmallocDesc) {
00929       if (strcmp(option, "dtor"))
00930          mmalloc_detach(fMmallocDesc);
00931 
00932       // If writable cannot access fMmallocDesc anymore since
00933       // it points to the just unmapped memory region. Any further
00934       // access to this TMapFile will cause a crash.
00935       if (!shadow->fWritable)
00936          fMmallocDesc = 0;
00937    }
00938 
00939    if (shadow->fFd != -1)
00940 #ifndef WIN32
00941       close(shadow->fFd);
00942 #else
00943       CloseHandle((HANDLE)shadow->fFd);
00944 #endif
00945 
00946    delete shadow;
00947 }
00948 
00949 //______________________________________________________________________________
00950 TMapFile *TMapFile::FindShadowMapFile()
00951 {
00952    // Returns shadow map file.
00953 
00954    R__LOCKGUARD2(gROOTMutex);
00955    TObjLink *lnk = ((TList *)gROOT->GetListOfMappedFiles())->LastLink();
00956    while (lnk) {
00957       TMapFile *mf = (TMapFile*)lnk->GetObject();
00958       if (mf->fVersion == -1 && fBaseAddr == mf->fBaseAddr && fSize == mf->fSize)
00959          return mf;
00960       lnk = lnk->Prev();
00961    }
00962    return 0;
00963 }
00964 
00965 //______________________________________________________________________________
00966 void TMapFile::Print(Option_t *) const
00967 {
00968    // Print some info about the mapped file.
00969 
00970    Printf("Memory mapped file:   %s", fName);
00971    Printf("Title:                %s", fTitle);
00972    if (fMmallocDesc) {
00973       Printf("Option:               %s", fOption);
00974       ULong_t size = (ULong_t)((struct mdesc *)fMmallocDesc)->top - fBaseAddr;
00975       Printf("Mapped Memory region: 0x%lx - 0x%lx (%.2f MB)", fBaseAddr, fBaseAddr + size,
00976              (float)size/1048576);
00977       Printf("Current breakval:     0x%lx", (ULong_t)GetBreakval());
00978    } else
00979       Printf("Option:               file closed");
00980 }
00981 
00982 //______________________________________________________________________________
00983 Bool_t TMapFile::IsFolder() const
00984 {
00985    // Returns kTRUE in case object is a folder (i.e. contains browsable lists).
00986 
00987    if (fMmallocDesc && fVersion > 0) return kTRUE;
00988    return kFALSE;
00989 }
00990 
00991 //______________________________________________________________________________
00992 void TMapFile::Browse(TBrowser *b)
00993 {
00994    // Browse contents of TMapFile.
00995 
00996    if (b && fMmallocDesc) {
00997 
00998       AcquireSemaphore();
00999 
01000       TMapRec *mr = GetFirst();
01001       TKeyMapFile *keymap;
01002       if (!fBrowseList) fBrowseList = new TList();
01003       while (OrgAddress(mr)) {
01004          keymap = (TKeyMapFile*)fBrowseList->FindObject(mr->GetName(fOffset));
01005          if (!keymap) {
01006             keymap = new TKeyMapFile(mr->GetName(fOffset),mr->GetClassName(fOffset),this);
01007             fBrowseList->Add(keymap);
01008          }
01009          b->Add(keymap, keymap->GetName());
01010          mr = mr->GetNext(fOffset);
01011       }
01012 
01013       ReleaseSemaphore();
01014 
01015    }
01016 }
01017 
01018 //______________________________________________________________________________
01019 Bool_t TMapFile::cd(const char *path)
01020 {
01021    // Cd to associated directory,
01022 
01023    if (fDirectory)
01024       return fDirectory->cd(path);
01025    return kFALSE;
01026 }
01027 
01028 //______________________________________________________________________________
01029 void TMapFile::ls(Option_t *) const
01030 {
01031    // List contents of TMapFile.
01032 
01033    if (fMmallocDesc) {
01034 
01035       ((TMapFile*)this)->AcquireSemaphore();
01036 
01037       Printf("%-20s %-20s %-10s", "Object", "Class", "Size");
01038       if (!fFirst)
01039          Printf("*** no objects stored in memory mapped file ***");
01040 
01041       TMapRec *mr = GetFirst();
01042       while (OrgAddress(mr)) {
01043          Printf("%-20s %-20s %-10d", mr->GetName(fOffset),
01044                 mr->GetClassName(fOffset), mr->fBufSize);
01045          mr = mr->GetNext(fOffset);
01046       }
01047 
01048       ((TMapFile*)this)->ReleaseSemaphore();
01049 
01050    }
01051 }
01052 
01053 //_______________________________________________________________________
01054 void TMapFile::SumBuffer(Int_t bufsize)
01055 {
01056    // Increment statistics for buffer sizes of objects in this file.
01057 
01058    fWritten++;
01059    fSumBuffer  += bufsize;
01060    fSum2Buffer += bufsize*bufsize;
01061 }
01062 
01063 //______________________________________________________________________________
01064 Int_t TMapFile::GetBestBuffer()
01065 {
01066    // Return the best buffer size for objects in this file.
01067    //
01068    // The best buffer size is estimated based on the current mean value
01069    // and standard deviation of all objects written so far to this file.
01070    // Returns mean value + one standard deviation.
01071 
01072    if (!fWritten) return TBuffer::kMinimalSize;
01073    Double_t mean = fSumBuffer/fWritten;
01074    Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer - mean*mean);
01075    return (Int_t)(mean + std::sqrt(rms2));
01076 }
01077 
01078 
01079 //______________________________________________________________________________
01080 TMapFile *TMapFile::Create(const char *name, Option_t *option, Int_t size,
01081                            const char *title)
01082 {
01083    // Create a memory mapped file. This opens a file (to which the
01084    // memory will be mapped) and attaches a memory region to it.
01085    // Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE"
01086    // or "READ" (see TFile). The default open mode is "READ". The size
01087    // argument specifies the maximum size of shared memory file in bytes.
01088    // TMapFile's can only be created via this method. Create() enforces that
01089    // a TMapFile is always on the memory mapped heap (when "NEW", "CREATE"
01090    // or "RECREATE" are used).
01091 
01092    TMapFile *newMapFile;
01093    new TMapFile(name, title, option, size, newMapFile);
01094 
01095    return newMapFile;
01096 }
01097 
01098 //______________________________________________________________________________
01099 void TMapFile::SetMapAddress(Long_t addr)
01100 {
01101    // Set preferred map address. Find out preferred map address as follows:
01102    // 1) Run consumer program to find the preferred map address:
01103    //       $ root
01104    //       root [0] m = TMapFile::Create("dummy.map", "recreate", 10000000);
01105    //       root [1] m.Print()
01106    //       Memory mapped file:   dummy.map
01107    //       Title:
01108    //       Option:               CREATE
01109    //       Mapped Memory region: 0x40b4c000 - 0x40d95f00 (2.29 MB)
01110    //       Current breakval:     0x40b53000
01111    //       root [2] .q
01112    //       $ rm dummy.map
01113    //    Remember begin of mapped region, i.e. 0x40b4c000
01114    //
01115    // 2) Add to producer program, just before creating the TMapFile:
01116    //       TMapFile::SetMapAddress(0x40b4c000);
01117    //
01118    // Repeat this if more than one map file is being used.
01119    //
01120    // The above procedure allow programs using, e.g., different number of
01121    // shared libraries (that cause the default mapping address to be
01122    // different) to create shared memory regions in the same location
01123    // without overwriting a shared library. The above assumes the consumer
01124    // program is larger (i.e. has more shared memory occupied) than the
01125    // producer. If this is not true inverse the procedure.
01126 
01127    fgMapAddress = addr;
01128 }
01129 
01130 //______________________________________________________________________________
01131 void *TMapFile::MapToAddress()
01132 {
01133    // Return the base address at which we would like the next TMapFile's
01134    // mapped data to start.
01135    //
01136    // For now, we let the system decide (start address 0). There are
01137    // a lot of issues to deal with here to make this work reasonably,
01138    // including:
01139    //
01140    // - Avoid memory collisions with existing mapped address spaces
01141    //
01142    // - Reclaim address spaces when their mmalloc heaps are unmapped
01143    //
01144    // - When mmalloc heaps are shared between processes they have to be
01145    //   mapped at the same addresses in each
01146    //
01147    // Once created, a mmalloc heap that is to be mapped back in must be
01148    // mapped at the original address.  I.E. each TMapFile will expect
01149    // to be remapped at it's original address. This becomes a problem if
01150    // the desired address is already in use.
01151 
01152 #ifdef R__HAVE_MMAP
01153    if (TStorage::HasCustomNewDelete())
01154       return (void *)fgMapAddress;
01155    else
01156       return (void *)-1;
01157 #else
01158    return (void *)-1;
01159 #endif
01160 }
01161 
01162 //______________________________________________________________________________
01163 void TMapFile::operator delete(void *ptr)
01164 {
01165    // Need special "operator delete" in which we close the shared memory.
01166    // This has to be done after the dtor chain has been finished.
01167 
01168    mmalloc_detach(fgMmallocDesc);
01169    fgMmallocDesc = 0;
01170 
01171    TObject::operator delete(ptr);
01172 }

Generated on Tue Jul 5 14:30:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1