// @(#)root/io:$Id$
// Author: Fons Rademakers   08/07/97

/*************************************************************************
 * 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.             *
 *************************************************************************/
#ifdef WIN32
#pragma optimize("",off)
#endif

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TMapFile                                                             //
//                                                                      //
// This class implements a shared memory region mapped to a file.       //
// Objects can be placed into this shared memory area using the Add()   //
// member function. To actually place a copy of the object is shared    //
// memory call Update() also whenever the mapped object(s) change(s)    //
// call Update() to put a fresh copy in the shared memory. This extra   //
// step is necessary since it is not possible to share objects with     //
// virtual pointers between processes (the vtbl ptr points to the       //
// originators unique address space and can not be used by the          //
// consumer process(es)). Consumer processes can map the memory region  //
// from this file and access the objects stored in it via the Get()     //
// method (which returns a copy of the object stored in the shared      //
// memory with correct vtbl ptr set). Only objects of classes with a    //
// Streamer() member function defined can be shared.                    //
//                                                                      //
// I know the current implementation is not ideal (you need to copy to  //
// and from the shared memory file) but the main problem is with the    //
// class' virtual_table pointer. This pointer points to a table unique  //
// for every process. Therefore, different options are:                 //
//   1) One could allocate an object directly in shared memory in the   //
//      producer, but the consumer still has to copy the object from    //
//      shared memory into a local object which has the correct vtbl    //
//      pointer for that process (copy ctor's can be used for creating  //
//      the local copy).                                                //
//   2) Another possibility is to only allow objects without virtual    //
//      functions in shared memory (like simple C structs), or to       //
//      forbid (how?) the consumer from calling any virtual functions   //
//      of the objects in shared memory.                                //
//   3) A last option is to copy the object internals to shared memory  //
//      and copy them again from there. This is what is done in the     //
//      TMapFile (using the object Streamer() to make a deep copy).     //
// Option 1) saves one copy, but requires solid copy ctor's (along the  //
// full inheritance chain) to rebuild the object in the consumer. Most  //
// classes don't provide these copy ctor's, especially not when objects //
// contain collections, etc. 2) is too limiting or dangerous (calling   //
// accidentally a virtual function will segv). So since we have a       //
// robust Streamer mechanism I opted for 3).                            //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#ifdef WIN32
#  include <windows.h>
#  include <process.h>
#  ifdef GetObject
#    undef GetObject
#  endif
#  define HAVE_SEMOP

# ifdef CreateSemaphore
#   undef CreateSemaphore
# endif

# ifdef AcquireSemaphore
#   undef AcquireSemaphore;
# endif

# ifdef ReleaseSemaphore
#   undef ReleaseSemaphore
# endif

# ifdef DeleteSemaphore
#   undef DeleteSemaphore
# endif

#else
#  define INVALID_HANDLE_VALUE -1
#endif

#include <fcntl.h>
#include <errno.h>

#include "TMapFile.h"
#include "TKeyMapFile.h"
#include "TDirectoryFile.h"
#include "TBrowser.h"
#include "TString.h"
#include "TSystem.h"
#include "TClass.h"
#include "TBufferFile.h"
#include "TVirtualMutex.h"
#include <cmath>

#if defined(R__UNIX) && !defined(R__MACOSX) && !defined(R__WINGCC)
#define HAVE_SEMOP
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#if defined(R__HPUX) || \
    defined (R__SOLARIS) || defined(R__AIX) || defined(R__HIUX) || \
    __GLIBC_MINOR__ > 0
union semun {
   int val;                      // value for SETVAL
   struct semid_ds *buf;         // buffer for IPC_STAT & IPC_SET
   ushort *array;                // array for GETALL & SETALL
};
#endif
#if defined(R__LINUX) || defined(R__LYNXOS) || defined(R__HURD)
#  define       SEM_A   0200     // alter permission
#  define       SEM_R   0400     // read permission
#endif
#endif


Long_t TMapFile::fgMapAddress = 0;
void  *TMapFile::fgMmallocDesc = 0;

//void *gMmallocDesc = 0; //is initialized in TClass.cxx



//______________________________________________________________________________
TMapRec::TMapRec(const char *name, const TObject *obj, Int_t size, void *buf)
{
   /// Constructor.
   fName      = StrDup(name);
   fClassName = 0;
   fObject    = (TObject*)obj;
   fBuffer    = buf;
   fBufSize   = size;
   fNext      = 0;
}

//______________________________________________________________________________
TMapRec::~TMapRec()
{
   // Destructor.
   delete [] fName;
   delete [] fClassName;
}

//______________________________________________________________________________
TObject *TMapRec::GetObject() const
{
   // This method returns a pointer to the original object. NOTE: this pointer
   // is only valid in the process that produces the shared memory file. In a
   // consumer process this pointer is illegal! Be careful.

   return fObject;
}




ClassImp(TMapFile)

//______________________________________________________________________________
TMapFile::TMapFile()
{
   // Default ctor. Does not much except setting some basic values.

   fFd          = -1;
   fVersion     = 0;
   fName        = 0;
   fTitle       = 0;
   fOption      = 0;
   fMmallocDesc = 0;
   fBaseAddr    = 0;
   fSize        = 0;
   fFirst       = 0;
   fLast        = 0;
   fOffset      = 0;
   fDirectory   = 0;
   fBrowseList  = 0;
   fWritable    = kFALSE;
   fSemaphore   = -1;
   fhSemaphore  = 0;
   fGetting     = 0;
   fWritten     = 0;
   fSumBuffer   = 0;
   fSum2Buffer  = 0;
}

//______________________________________________________________________________
TMapFile::TMapFile(const char *name, const char *title, Option_t *option,
                   Int_t size, TMapFile *&newMapFile)
{
   // Create a memory mapped file. This opens a file (to which the
   // memory will be mapped) and attaches a memory region to it.
   // Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE" or
   // "READ" (see TFile). The default open mode is "READ". The size
   // argument specifies the maximum size of shared memory file in bytes.
   // This protected ctor is called via the static Create() method.

#ifndef WIN32
   fFd          = -1;
   fSemaphore   = -1;
   fhSemaphore  = 0;
#else
   fFd          = (Int_t) INVALID_HANDLE_VALUE;
   fSemaphore   = (Int_t) INVALID_HANDLE_VALUE;
#endif
   fMmallocDesc = 0;
   fSize        = size;
   fFirst       = 0;
   fOffset      = 0;
   fVersion     = gROOT->GetVersionInt();
   fTitle       = StrDup(title);
   fOption      = StrDup(option);
   fDirectory   = 0;
   fBrowseList  = 0;
   fGetting     = 0;
   fWritten     = 0;
   fSumBuffer   = 0;
   fSum2Buffer  = 0;

   char  *cleanup = 0;
   Bool_t create  = kFALSE;
   Bool_t recreate, update, read;

   {
      TString opt = option;

      if (!opt.CompareTo("NEW", TString::kIgnoreCase) ||
          !opt.CompareTo("CREATE", TString::kIgnoreCase))
         create = kTRUE;
      recreate = opt.CompareTo("RECREATE", TString::kIgnoreCase)
                 ? kFALSE : kTRUE;
      update   = opt.CompareTo("UPDATE", TString::kIgnoreCase)
                 ? kFALSE : kTRUE;
      read     = opt.CompareTo("READ", TString::kIgnoreCase)
                 ? kFALSE : kTRUE;
      if (!create && !recreate && !update && !read) {
         read    = kTRUE;
         delete [] fOption;
         fOption = StrDup("READ");
      }
   }

   const char *fname;
   if ((fname = gSystem->ExpandPathName(name))) {
      fName = StrDup(fname);
      delete [] (char*)fname;
      fname = fName;
   } else {
      Error("TMapFile", "error expanding path %s", fname);
      goto zombie;
   }

   if (recreate) {
      if (!gSystem->AccessPathName(fname, kFileExists))
         gSystem->Unlink(fname);
      recreate = kFALSE;
      create   = kTRUE;
      delete [] fOption;
      fOption  = StrDup("CREATE");
   }
   if (create && !gSystem->AccessPathName(fname, kFileExists)) {
      Error("TMapFile", "file %s already exists", fname);
      goto zombie;
   }
   if (update) {
      if (gSystem->AccessPathName(fname, kFileExists)) {
         update = kFALSE;
         create = kTRUE;
      }
      if (update && gSystem->AccessPathName(fname, kWritePermission)) {
         Error("TMapFile", "no write permission, could not open file %s", fname);
         goto zombie;
      }
   }
   if (read) {
      if (gSystem->AccessPathName(fname, kFileExists)) {
         Error("TMapFile", "file %s does not exist", fname);
         goto zombie;
      }
      if (gSystem->AccessPathName(fname, kReadPermission)) {
         Error("TMapFile", "no read permission, could not open file %s", fname);
         goto zombie;
      }
   }

   // Open file to which memory will be mapped
   if (create || update) {
#ifndef WIN32
      fFd = open(fname, O_RDWR | O_CREAT, 0644);
#else
      fFd = (Int_t) CreateFile(fname,                    // pointer to name of the file
                     GENERIC_WRITE | GENERIC_READ,       // access (read-write) mode
                     FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
                     NULL,                               // pointer to security attributes
                     OPEN_ALWAYS,                        // how to create
                     FILE_ATTRIBUTE_TEMPORARY,           // file attributes
                     (HANDLE) NULL);                     // handle to file with attributes to copy
#endif
      if (fFd == (Int_t)INVALID_HANDLE_VALUE) {
         SysError("TMapFile", "file %s can not be opened", fname);
         goto zombie;
      }
      fWritable = kTRUE;
   } else {
#ifndef WIN32
      fFd = open(fname, O_RDONLY);
#else
      fFd = (Int_t) CreateFile(fname,                    // pointer to name of the file
                     GENERIC_READ,                       // access (read-write) mode
                     FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
                     NULL,                               // pointer to security attributes
                     OPEN_EXISTING,                      // how to create
                     FILE_ATTRIBUTE_TEMPORARY,           // file attributes
                     (HANDLE) NULL);                     // handle to file with attributes to copy
#endif
      if (fFd == (Int_t)INVALID_HANDLE_VALUE) {
         SysError("TMapFile", "file %s can not be opened for reading", fname);
         goto zombie;
      }
      fWritable = kFALSE;
   }

   // Attach memory region to file.
   void *mapto;
   TMapFile *mapfil;

   if (((mapto = MapToAddress()) == (void *)-1) ||
#ifndef WIN32
       ((fMmallocDesc = mmalloc_attach(fFd, mapto, fSize)) == 0)) {
#else
       ((fMmallocDesc = mmalloc_attach((HANDLE) fFd, mapto, fSize)) == 0)) {
#endif

      if (mapto == (void *)-1) {
         Error("TMapFile", "no memory mapped file capability available\n"
                           "Use rootn.exe or link application against \"-lNew\"");
      } else {
         if (fMmallocDesc == 0 && fWritable)
            Error("TMapFile", "mapped file not in mmalloc format or\n"
                              "already open in RW mode by another process");
         if (fMmallocDesc == 0 && !fWritable)
            Error("TMapFile", "mapped file not in mmalloc format");
      }
#ifndef WIN32
      close(fFd);
#else
      CloseHandle((HANDLE) fFd);
#endif
      fFd = -1;
      if (create)
         gSystem->Unlink(fname);
      goto zombie;

   } else if ((mapfil = (TMapFile *) mmalloc_getkey(fMmallocDesc, 0)) != 0) {

      // File contains mmalloc heap. If we are in write mode and mapped
      // file already connected in write mode switch to read-only mode.
      // Check if ROOT versions are compatible.
      // If so update mapped version of TMapFile to reflect current
      // situation (only if not opened in READ mode).
      if (mapfil->fVersion != fVersion) {
         Error("TMapFile", "map file %s (%d) incompatible with current ROOT version (%d)",
               fname, mapfil->fVersion, fVersion);
         mmalloc_detach(fMmallocDesc);
#ifndef WIN32
         close(fFd);
#else
         CloseHandle((HANDLE) fFd);
#endif
         fFd = -1;
         fMmallocDesc = 0;
         goto zombie;
      }

      if (mapfil->fWritable && fWritable) {
         Warning("TMapFile", "map file already open in write mode, opening in read-only mode");
         fWritable = kFALSE;
      }

      fBaseAddr = mapfil->fBaseAddr;
      fSize     = mapfil->fSize;

      if (fWritable) {
         // create new TMapFile object in mapped heap to get correct vtbl ptr
         CreateSemaphore();
         gMmallocDesc = fMmallocDesc;
         TMapFile *mf = new TMapFile(*mapfil);
         mf->fFd        = fFd;
         mf->fWritable  = kTRUE;
         cleanup        = mf->fOption;
         mf->fOption    = StrDup(fOption);
         mf->fSemaphore = fSemaphore;
#ifdef WIN32
         mf->CreateSemaphore(fSemaphore);
#endif
         mmalloc_setkey(fMmallocDesc, 0, mf);
         gMmallocDesc = 0;
         mapfil = mf;
      } else {
         gMmallocDesc = 0;    // make sure we are in sbrk heap
         fOffset      = ((struct mdesc *) fMmallocDesc)->offset;
         TMapFile *mf = new TMapFile(*mapfil, fOffset);
         delete [] mf->fOption;
         mf->fFd          = fFd;
         mf->fOption      = StrDup("READ");
         mf->fMmallocDesc = fMmallocDesc;
         mf->fWritable    = kFALSE;
         mapfil = mf;
      }

      // store shadow mapfile (it contains the real fFd in case map
      // is not writable)
      fVersion  = -1;   // make this the shadow map file
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetListOfMappedFiles()->AddLast(this);

   } else {

      // New file. If the file is writable create a new copy of the
      // TMapFile which will now be allocated on the memory mapped heap.
      if (!fWritable) {
         Error("TMapFile", "map file is not writable");
         mmalloc_detach(fMmallocDesc);
#ifndef WIN32
         close(fFd);
#else
         CloseHandle((HANDLE) fFd);
#endif
         fFd = -1;
         fMmallocDesc = 0;
         goto zombie;
      }

      fBaseAddr = (ULong_t)((struct mdesc *) fMmallocDesc)->base;

      CreateSemaphore();

      gMmallocDesc = fMmallocDesc;

      mapfil = new TMapFile(*this);
      mmalloc_setkey(fMmallocDesc, 0, mapfil);

      gMmallocDesc = 0;

      // store shadow mapfile
      fVersion  = -1;   // make this the shadow map file
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetListOfMappedFiles()->AddLast(this);

   }

   mapfil->InitDirectory();
   {
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetListOfMappedFiles()->AddFirst(mapfil);
   }

   if (cleanup) delete [] cleanup;

   newMapFile = mapfil;

   return;

zombie:
   // error in file opening occured, make this object a zombie
   MakeZombie();
   newMapFile   = this;
   gMmallocDesc = 0;
}

//______________________________________________________________________________
TMapFile::TMapFile(const TMapFile &f, Long_t offset) : TObject(f)
{
   // Private copy ctor. Used by the the ctor to create a new version
   // of TMapFile in the memory mapped heap. It's main purpose is to
   // correctly create the string data members.

   fFd          = f.fFd;
   fVersion     = f.fVersion;
   fName        = StrDup((char *)((Long_t)f.fName + offset));
   fTitle       = StrDup((char *)((Long_t)f.fTitle + offset));
   fOption      = StrDup((char *)((Long_t)f.fOption + offset));
   fMmallocDesc = f.fMmallocDesc;
   fBaseAddr    = f.fBaseAddr;
   fSize        = f.fSize;
   fFirst       = f.fFirst;
   fLast        = f.fLast;
   fWritable    = f.fWritable;
   fSemaphore   = f.fSemaphore;
   fOffset      = offset;
   fDirectory   = 0;
   fBrowseList  = 0;
   fGetting     = 0;
   fWritten     = f.fWritten;
   fSumBuffer   = f.fSumBuffer;
   fSum2Buffer  = f.fSum2Buffer;
#ifdef WIN32
   CreateSemaphore(fSemaphore);
#else
   fhSemaphore = f.fhSemaphore;
#endif
}

//______________________________________________________________________________
TMapFile::~TMapFile()
{
   // TMapFiles may not be deleted, since we want to keep the complete
   // TMapFile object in the mapped file for later re-use. To enforce this
   // the delete operator has been made private. Use Close() to properly
   // terminate a TMapFile (also done via the TROOT dtor).

   if (fDirectory == gDirectory) gDirectory = gROOT;
   delete fDirectory; fDirectory = 0;
   if (fBrowseList) fBrowseList->Delete();
   delete fBrowseList; fBrowseList = 0;

   // if shadow map file we are done here
   if (fVersion == -1)
      return;

   // Writable mapfile is allocated in mapped memory. This object should
   // not be deleted by ::operator delete(), because it is needed if we
   // want to connect later to the file again.
   if (fWritable)
      TObject::SetDtorOnly(this);

   Close("dtor");

   fgMmallocDesc = fMmallocDesc;
}

//______________________________________________________________________________
void TMapFile::InitDirectory()
{
   // Create the directory associated to this mapfile

   gDirectory = 0;
   fDirectory = new TDirectoryFile();
   fDirectory->SetName(GetName());
   fDirectory->SetTitle(GetTitle());
   fDirectory->Build();
   fDirectory->SetMother(this);
   gDirectory = fDirectory;
}

//______________________________________________________________________________
void TMapFile::Add(const TObject *obj, const char *name)
{
   // Add an object to the list of objects to be stored in shared memory.
   // To place the object actually into shared memory call Update().

   if (!fWritable || !fMmallocDesc) return;

   Bool_t lock = fGetting != obj ? kTRUE : kFALSE;

   if (lock)
      AcquireSemaphore();

   gMmallocDesc = fMmallocDesc;

   const char *n;
   if (name && *name)
      n = name;
   else
      n = obj->GetName();

   if (Remove(n, kFALSE)) {
      //Warning("Add", "replaced object with same name %s", n);
   }

   TMapRec *mr = new TMapRec(n, obj, 0, 0);
   if (!fFirst) {
      fFirst = mr;
      fLast  = mr;
   } else {
      fLast->fNext = mr;
      fLast        = mr;
   }

   gMmallocDesc = 0;

   if (lock)
      ReleaseSemaphore();
}

//______________________________________________________________________________
void TMapFile::Update(TObject *obj)
{
   // Update an object (or all objects, if obj == 0) in shared memory.

   if (!fWritable || !fMmallocDesc) return;

   AcquireSemaphore();

   gMmallocDesc = fMmallocDesc;

   Bool_t all = (obj == 0) ? kTRUE : kFALSE;

   TMapRec *mr = fFirst;
   while (mr) {
      if (all || mr->fObject == obj) {
         TBufferFile *b;
         if (!mr->fBufSize) {
            b = new TBufferFile(TBuffer::kWrite, GetBestBuffer());
            mr->fClassName = StrDup(mr->fObject->ClassName());
         } else
            b = new TBufferFile(TBuffer::kWrite, mr->fBufSize, mr->fBuffer);
         b->MapObject(mr->fObject);  //register obj in map to handle self reference
         mr->fObject->Streamer(*b);
         mr->fBufSize = b->BufferSize();
         mr->fBuffer  = b->Buffer();
         SumBuffer(b->Length());
         b->DetachBuffer();
         delete b;
      }
      mr = mr->fNext;
   }

   gMmallocDesc = 0;

   ReleaseSemaphore();
}

//______________________________________________________________________________
TObject *TMapFile::Remove(TObject *obj, Bool_t lock)
{
   // Remove object from shared memory. Returns pointer to removed
   // object if successful, 0 otherwise.

   if (!fWritable || !fMmallocDesc) return 0;

   if (lock)
      AcquireSemaphore();

   TObject *retObj = 0;
   TMapRec *prev = 0, *mr = fFirst;
   while (mr) {
      if (mr->fObject == obj) {
         if (mr == fFirst) {
            fFirst = mr->fNext;
            if (mr == fLast)
               fLast = 0;
         } else {
            prev->fNext = mr->fNext;
            if (mr == fLast)
               fLast = prev;
         }
         retObj = obj;
         delete mr;
         break;
      }
      prev = mr;
      mr   = mr->fNext;
   }

   if (lock)
      ReleaseSemaphore();

   return retObj;
}

//______________________________________________________________________________
TObject *TMapFile::Remove(const char *name, Bool_t lock)
{
   // Remove object by name from shared memory. Returns pointer to removed
   // object if successful, 0 otherwise.

   if (!fWritable || !fMmallocDesc) return 0;

   if (lock)
      AcquireSemaphore();

   TObject *retObj = 0;
   TMapRec *prev = 0, *mr = fFirst;
   while (mr) {
      if (!strcmp(mr->fName, name)) {
         if (mr == fFirst) {
            fFirst = mr->fNext;
            if (mr == fLast)
               fLast = 0;
         } else {
            prev->fNext = mr->fNext;
            if (mr == fLast)
               fLast = prev;
         }
         retObj = mr->fObject;
         delete mr;
         break;
      }
      prev = mr;
      mr   = mr->fNext;
   }

   if (lock)
      ReleaseSemaphore();

   return retObj;
}

//______________________________________________________________________________
void TMapFile::RemoveAll()
{
   // Remove all objects from shared memory.

   if (!fWritable || !fMmallocDesc) return;

   AcquireSemaphore();

   TMapRec *mr = fFirst;
   while (mr) {
      TMapRec *t = mr;
      mr = mr->fNext;
      delete t;
   }
   fFirst = fLast = 0;

   ReleaseSemaphore();
}

//______________________________________________________________________________
TObject *TMapFile::Get(const char *name, TObject *delObj)
{
   // Return pointer to object retrieved from shared memory. The object must
   // be deleted after use. If delObj is a pointer to a previously allocated
   // object it will be deleted. Returns 0 in case object with the given
   // name does not exist.

   if (!fMmallocDesc) return 0;

   AcquireSemaphore();

   delete delObj;

   TObject *obj = 0;
   TMapRec *mr = GetFirst();
   while (OrgAddress(mr)) {
      if (!strcmp(mr->GetName(fOffset), name)) {
         if (!mr->fBufSize) goto release;
         TClass *cl = TClass::GetClass(mr->GetClassName(fOffset));
         if (!cl) {
            Error("Get", "unknown class %s", mr->GetClassName(fOffset));
            goto release;
         }

         obj = (TObject *)cl->New();
         if (!obj) {
            Error("Get", "cannot create new object of class %s", mr->GetClassName(fOffset));
            goto release;
         }

         fGetting = obj;
         TBufferFile *b = new TBufferFile(TBuffer::kRead, mr->fBufSize, mr->GetBuffer(fOffset));
         b->MapObject(obj);  //register obj in map to handle self reference
         obj->Streamer(*b);
         b->DetachBuffer();
         delete b;
         fGetting = 0;
         goto release;
      }
      mr = mr->GetNext(fOffset);
   }

release:
   ReleaseSemaphore();

   return obj;
}

//______________________________________________________________________________
#ifndef WIN32
void TMapFile::CreateSemaphore(int)
#else
void TMapFile::CreateSemaphore(int pid)
#endif
{
   // Create semaphore used for synchronizing access to shared memory.

#ifdef HAVE_SEMOP
#ifndef WIN32
   // create semaphore to synchronize access (should use read/write lock)
   fSemaphore = semget(IPC_PRIVATE, 1, SEM_R|SEM_A|(SEM_R>>3)|(SEM_A>>3)|
                                       (SEM_R>>6)|(SEM_A>>6));

   // set semaphore to 1
   if (fSemaphore != -1) {
      union semun set;
      set.val = 1;
      semctl(fSemaphore, 0, SETVAL, set);
   }
#else
   char buffer[] ="ROOT_Semaphore_xxxxxxxx";
   int lbuf = strlen(buffer);
   if (!pid) fSemaphore = getpid();
   fhSemaphore = (ULong_t)CreateMutex(NULL,FALSE,itoa(fSemaphore,&buffer[lbuf-8],16));
   if (fhSemaphore == 0) fSemaphore = (Int_t)INVALID_HANDLE_VALUE;
#endif
#endif
}

//______________________________________________________________________________
void TMapFile::DeleteSemaphore()
{
   // Delete the semaphore.

#ifdef HAVE_SEMOP
   // remove semaphore
#ifndef WIN32
   if (fSemaphore != -1) {
      int semid  = fSemaphore;
      fSemaphore = -1;
      union semun set;
      set.val = 0;
      semctl(semid, 0, IPC_RMID, set);
   }
#else
   if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE) {
      CloseHandle((HANDLE)fhSemaphore);
      fhSemaphore = 0;
      fSemaphore  = (Int_t)INVALID_HANDLE_VALUE;
   }
#endif
#endif
}

//______________________________________________________________________________
Int_t TMapFile::AcquireSemaphore()
{
   // Acquire semaphore. Returns 0 if OK, -1 on error.

#ifdef HAVE_SEMOP
#ifndef WIN32
   if (fSemaphore != -1) {
      struct sembuf buf = { 0, -1, SEM_UNDO };
      int intr = 0;
again:
      if (semop(fSemaphore, &buf, 1) == -1) {
#if defined(R__FBSD) || defined(R__OBSD)
         if (TSystem::GetErrno() == EINVAL)
#else
         if (TSystem::GetErrno() == EIDRM)
#endif
            fSemaphore = -1;
#if !defined(R__FBSD)
         if (TSystem::GetErrno() == EINTR) {
            if (intr > 2)
               return -1;
            TSystem::ResetErrno();
            intr++;
            goto again;
         }
#endif
      }
   }
#else
   // Enter Critical section to "write" lock
   if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE)
      WaitForSingleObject((HANDLE)fhSemaphore,INFINITE);
#endif
#endif

   // file might have grown, update mapping on reader to new size
   if (!fWritable && fMmallocDesc) {
      if (mmalloc_update_mapping(fMmallocDesc) == -1)
         Error("AcquireSemaphore", "cannot update mapping");
   }

   return 0;
}

//______________________________________________________________________________
Int_t TMapFile::ReleaseSemaphore()
{
   // Release semaphore. Returns 0 if OK, -1 on error.

#ifdef HAVE_SEMOP
#ifndef WIN32
   if (fSemaphore != -1) {
      struct sembuf buf = { 0, 1, SEM_UNDO };
      if (semop(fSemaphore, &buf, 1) == -1) {
#if defined(R__FBSD) || defined(R__OBSD)
         if (TSystem::GetErrno() == EINVAL)
#else
         if (TSystem::GetErrno() == EIDRM)
#endif
            fSemaphore = -1;
      }
   }
#else
   if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE)
      ReleaseMutex((HANDLE)fhSemaphore);
#endif
#endif
   return 0;
}

//______________________________________________________________________________
void TMapFile::Close(Option_t *option)
{
   // Close a mapped file. First detach mapped memory then close file.
   // No member functions of a TMapFile that was opened in write mode
   // may be called after Close() (this includes, of course, "delete" which
   // would call the dtors). The option="dtor" is only used when called
   // via the ~TMapFile.

   if (!fMmallocDesc) return;

   TMapFile *shadow = FindShadowMapFile();
   if (!shadow) {
      Error("Close", "shadow map == 0, should never happen!");
      return;
   }

   {
      R__LOCKGUARD2(gROOTMutex);
      gROOT->GetListOfMappedFiles()->Remove(shadow);
      gROOT->GetListOfMappedFiles()->Remove(this);
   }

   if (shadow->fWritable) {
      fWritable = kFALSE;
      DeleteSemaphore();
   }

   if (fMmallocDesc) {
      if (strcmp(option, "dtor"))
         mmalloc_detach(fMmallocDesc);

      // If writable cannot access fMmallocDesc anymore since
      // it points to the just unmapped memory region. Any further
      // access to this TMapFile will cause a crash.
      if (!shadow->fWritable)
         fMmallocDesc = 0;
   }

   if (shadow->fFd != -1)
#ifndef WIN32
      close(shadow->fFd);
#else
      CloseHandle((HANDLE)shadow->fFd);
#endif

   delete shadow;
}

//______________________________________________________________________________
TMapFile *TMapFile::FindShadowMapFile()
{
   // Returns shadow map file.

   R__LOCKGUARD2(gROOTMutex);
   TObjLink *lnk = ((TList *)gROOT->GetListOfMappedFiles())->LastLink();
   while (lnk) {
      TMapFile *mf = (TMapFile*)lnk->GetObject();
      if (mf->fVersion == -1 && fBaseAddr == mf->fBaseAddr && fSize == mf->fSize)
         return mf;
      lnk = lnk->Prev();
   }
   return 0;
}

//______________________________________________________________________________
void TMapFile::Print(Option_t *) const
{
   // Print some info about the mapped file.

   Printf("Memory mapped file:   %s", fName);
   Printf("Title:                %s", fTitle);
   if (fMmallocDesc) {
      Printf("Option:               %s", fOption);
      ULong_t size = (ULong_t)((struct mdesc *)fMmallocDesc)->top - fBaseAddr;
      Printf("Mapped Memory region: 0x%lx - 0x%lx (%.2f MB)", fBaseAddr, fBaseAddr + size,
             (float)size/1048576);
      Printf("Current breakval:     0x%lx", (ULong_t)GetBreakval());
   } else
      Printf("Option:               file closed");
}

//______________________________________________________________________________
Bool_t TMapFile::IsFolder() const
{
   // Returns kTRUE in case object is a folder (i.e. contains browsable lists).

   if (fMmallocDesc && fVersion > 0) return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TMapFile::Browse(TBrowser *b)
{
   // Browse contents of TMapFile.

   if (b && fMmallocDesc) {

      AcquireSemaphore();

      TMapRec *mr = GetFirst();
      TKeyMapFile *keymap;
      if (!fBrowseList) fBrowseList = new TList();
      while (OrgAddress(mr)) {
         keymap = (TKeyMapFile*)fBrowseList->FindObject(mr->GetName(fOffset));
         if (!keymap) {
            keymap = new TKeyMapFile(mr->GetName(fOffset),mr->GetClassName(fOffset),this);
            fBrowseList->Add(keymap);
         }
         b->Add(keymap, keymap->GetName());
         mr = mr->GetNext(fOffset);
      }

      ReleaseSemaphore();

   }
}

//______________________________________________________________________________
Bool_t TMapFile::cd(const char *path)
{
   // Cd to associated directory,

   if (fDirectory)
      return fDirectory->cd(path);
   return kFALSE;
}

//______________________________________________________________________________
void TMapFile::ls(Option_t *) const
{
   // List contents of TMapFile.

   if (fMmallocDesc) {

      ((TMapFile*)this)->AcquireSemaphore();

      Printf("%-20s %-20s %-10s", "Object", "Class", "Size");
      if (!fFirst)
         Printf("*** no objects stored in memory mapped file ***");

      TMapRec *mr = GetFirst();
      while (OrgAddress(mr)) {
         Printf("%-20s %-20s %-10d", mr->GetName(fOffset),
                mr->GetClassName(fOffset), mr->fBufSize);
         mr = mr->GetNext(fOffset);
      }

      ((TMapFile*)this)->ReleaseSemaphore();

   }
}

//_______________________________________________________________________
void TMapFile::SumBuffer(Int_t bufsize)
{
   // Increment statistics for buffer sizes of objects in this file.

   fWritten++;
   fSumBuffer  += bufsize;
   fSum2Buffer += bufsize*bufsize;
}

//______________________________________________________________________________
Int_t TMapFile::GetBestBuffer()
{
   // Return the best buffer size for objects in this file.
   //
   // The best buffer size is estimated based on the current mean value
   // and standard deviation of all objects written so far to this file.
   // Returns mean value + one standard deviation.

   if (!fWritten) return TBuffer::kMinimalSize;
   Double_t mean = fSumBuffer/fWritten;
   Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer - mean*mean);
   return (Int_t)(mean + std::sqrt(rms2));
}


//______________________________________________________________________________
TMapFile *TMapFile::Create(const char *name, Option_t *option, Int_t size,
                           const char *title)
{
   // Create a memory mapped file. This opens a file (to which the
   // memory will be mapped) and attaches a memory region to it.
   // Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE"
   // or "READ" (see TFile). The default open mode is "READ". The size
   // argument specifies the maximum size of shared memory file in bytes.
   // TMapFile's can only be created via this method. Create() enforces that
   // a TMapFile is always on the memory mapped heap (when "NEW", "CREATE"
   // or "RECREATE" are used).

   TMapFile *newMapFile;
   new TMapFile(name, title, option, size, newMapFile);

   return newMapFile;
}

//______________________________________________________________________________
void TMapFile::SetMapAddress(Long_t addr)
{
   // Set preferred map address. Find out preferred map address as follows:
   // 1) Run consumer program to find the preferred map address:
   //       $ root
   //       root [0] m = TMapFile::Create("dummy.map", "recreate", 10000000);
   //       root [1] m.Print()
   //       Memory mapped file:   dummy.map
   //       Title:
   //       Option:               CREATE
   //       Mapped Memory region: 0x40b4c000 - 0x40d95f00 (2.29 MB)
   //       Current breakval:     0x40b53000
   //       root [2] .q
   //       $ rm dummy.map
   //    Remember begin of mapped region, i.e. 0x40b4c000
   //
   // 2) Add to producer program, just before creating the TMapFile:
   //       TMapFile::SetMapAddress(0x40b4c000);
   //
   // Repeat this if more than one map file is being used.
   //
   // The above procedure allow programs using, e.g., different number of
   // shared libraries (that cause the default mapping address to be
   // different) to create shared memory regions in the same location
   // without overwriting a shared library. The above assumes the consumer
   // program is larger (i.e. has more shared memory occupied) than the
   // producer. If this is not true inverse the procedure.

   fgMapAddress = addr;
}

//______________________________________________________________________________
void *TMapFile::MapToAddress()
{
   // Return the base address at which we would like the next TMapFile's
   // mapped data to start.
   //
   // For now, we let the system decide (start address 0). There are
   // a lot of issues to deal with here to make this work reasonably,
   // including:
   //
   // - Avoid memory collisions with existing mapped address spaces
   //
   // - Reclaim address spaces when their mmalloc heaps are unmapped
   //
   // - When mmalloc heaps are shared between processes they have to be
   //   mapped at the same addresses in each
   //
   // Once created, a mmalloc heap that is to be mapped back in must be
   // mapped at the original address.  I.E. each TMapFile will expect
   // to be remapped at it's original address. This becomes a problem if
   // the desired address is already in use.

#ifdef R__HAVE_MMAP
   if (TStorage::HasCustomNewDelete())
      return (void *)fgMapAddress;
   else
      return (void *)-1;
#else
   return (void *)-1;
#endif
}

//______________________________________________________________________________
void TMapFile::operator delete(void *ptr)
{
   // Need special "operator delete" in which we close the shared memory.
   // This has to be done after the dtor chain has been finished.

   mmalloc_detach(fgMmallocDesc);
   fgMmallocDesc = 0;

   TObject::operator delete(ptr);
}
 TMapFile.cxx:1
 TMapFile.cxx:2
 TMapFile.cxx:3
 TMapFile.cxx:4
 TMapFile.cxx:5
 TMapFile.cxx:6
 TMapFile.cxx:7
 TMapFile.cxx:8
 TMapFile.cxx:9
 TMapFile.cxx:10
 TMapFile.cxx:11
 TMapFile.cxx:12
 TMapFile.cxx:13
 TMapFile.cxx:14
 TMapFile.cxx:15
 TMapFile.cxx:16
 TMapFile.cxx:17
 TMapFile.cxx:18
 TMapFile.cxx:19
 TMapFile.cxx:20
 TMapFile.cxx:21
 TMapFile.cxx:22
 TMapFile.cxx:23
 TMapFile.cxx:24
 TMapFile.cxx:25
 TMapFile.cxx:26
 TMapFile.cxx:27
 TMapFile.cxx:28
 TMapFile.cxx:29
 TMapFile.cxx:30
 TMapFile.cxx:31
 TMapFile.cxx:32
 TMapFile.cxx:33
 TMapFile.cxx:34
 TMapFile.cxx:35
 TMapFile.cxx:36
 TMapFile.cxx:37
 TMapFile.cxx:38
 TMapFile.cxx:39
 TMapFile.cxx:40
 TMapFile.cxx:41
 TMapFile.cxx:42
 TMapFile.cxx:43
 TMapFile.cxx:44
 TMapFile.cxx:45
 TMapFile.cxx:46
 TMapFile.cxx:47
 TMapFile.cxx:48
 TMapFile.cxx:49
 TMapFile.cxx:50
 TMapFile.cxx:51
 TMapFile.cxx:52
 TMapFile.cxx:53
 TMapFile.cxx:54
 TMapFile.cxx:55
 TMapFile.cxx:56
 TMapFile.cxx:57
 TMapFile.cxx:58
 TMapFile.cxx:59
 TMapFile.cxx:60
 TMapFile.cxx:61
 TMapFile.cxx:62
 TMapFile.cxx:63
 TMapFile.cxx:64
 TMapFile.cxx:65
 TMapFile.cxx:66
 TMapFile.cxx:67
 TMapFile.cxx:68
 TMapFile.cxx:69
 TMapFile.cxx:70
 TMapFile.cxx:71
 TMapFile.cxx:72
 TMapFile.cxx:73
 TMapFile.cxx:74
 TMapFile.cxx:75
 TMapFile.cxx:76
 TMapFile.cxx:77
 TMapFile.cxx:78
 TMapFile.cxx:79
 TMapFile.cxx:80
 TMapFile.cxx:81
 TMapFile.cxx:82
 TMapFile.cxx:83
 TMapFile.cxx:84
 TMapFile.cxx:85
 TMapFile.cxx:86
 TMapFile.cxx:87
 TMapFile.cxx:88
 TMapFile.cxx:89
 TMapFile.cxx:90
 TMapFile.cxx:91
 TMapFile.cxx:92
 TMapFile.cxx:93
 TMapFile.cxx:94
 TMapFile.cxx:95
 TMapFile.cxx:96
 TMapFile.cxx:97
 TMapFile.cxx:98
 TMapFile.cxx:99
 TMapFile.cxx:100
 TMapFile.cxx:101
 TMapFile.cxx:102
 TMapFile.cxx:103
 TMapFile.cxx:104
 TMapFile.cxx:105
 TMapFile.cxx:106
 TMapFile.cxx:107
 TMapFile.cxx:108
 TMapFile.cxx:109
 TMapFile.cxx:110
 TMapFile.cxx:111
 TMapFile.cxx:112
 TMapFile.cxx:113
 TMapFile.cxx:114
 TMapFile.cxx:115
 TMapFile.cxx:116
 TMapFile.cxx:117
 TMapFile.cxx:118
 TMapFile.cxx:119
 TMapFile.cxx:120
 TMapFile.cxx:121
 TMapFile.cxx:122
 TMapFile.cxx:123
 TMapFile.cxx:124
 TMapFile.cxx:125
 TMapFile.cxx:126
 TMapFile.cxx:127
 TMapFile.cxx:128
 TMapFile.cxx:129
 TMapFile.cxx:130
 TMapFile.cxx:131
 TMapFile.cxx:132
 TMapFile.cxx:133
 TMapFile.cxx:134
 TMapFile.cxx:135
 TMapFile.cxx:136
 TMapFile.cxx:137
 TMapFile.cxx:138
 TMapFile.cxx:139
 TMapFile.cxx:140
 TMapFile.cxx:141
 TMapFile.cxx:142
 TMapFile.cxx:143
 TMapFile.cxx:144
 TMapFile.cxx:145
 TMapFile.cxx:146
 TMapFile.cxx:147
 TMapFile.cxx:148
 TMapFile.cxx:149
 TMapFile.cxx:150
 TMapFile.cxx:151
 TMapFile.cxx:152
 TMapFile.cxx:153
 TMapFile.cxx:154
 TMapFile.cxx:155
 TMapFile.cxx:156
 TMapFile.cxx:157
 TMapFile.cxx:158
 TMapFile.cxx:159
 TMapFile.cxx:160
 TMapFile.cxx:161
 TMapFile.cxx:162
 TMapFile.cxx:163
 TMapFile.cxx:164
 TMapFile.cxx:165
 TMapFile.cxx:166
 TMapFile.cxx:167
 TMapFile.cxx:168
 TMapFile.cxx:169
 TMapFile.cxx:170
 TMapFile.cxx:171
 TMapFile.cxx:172
 TMapFile.cxx:173
 TMapFile.cxx:174
 TMapFile.cxx:175
 TMapFile.cxx:176
 TMapFile.cxx:177
 TMapFile.cxx:178
 TMapFile.cxx:179
 TMapFile.cxx:180
 TMapFile.cxx:181
 TMapFile.cxx:182
 TMapFile.cxx:183
 TMapFile.cxx:184
 TMapFile.cxx:185
 TMapFile.cxx:186
 TMapFile.cxx:187
 TMapFile.cxx:188
 TMapFile.cxx:189
 TMapFile.cxx:190
 TMapFile.cxx:191
 TMapFile.cxx:192
 TMapFile.cxx:193
 TMapFile.cxx:194
 TMapFile.cxx:195
 TMapFile.cxx:196
 TMapFile.cxx:197
 TMapFile.cxx:198
 TMapFile.cxx:199
 TMapFile.cxx:200
 TMapFile.cxx:201
 TMapFile.cxx:202
 TMapFile.cxx:203
 TMapFile.cxx:204
 TMapFile.cxx:205
 TMapFile.cxx:206
 TMapFile.cxx:207
 TMapFile.cxx:208
 TMapFile.cxx:209
 TMapFile.cxx:210
 TMapFile.cxx:211
 TMapFile.cxx:212
 TMapFile.cxx:213
 TMapFile.cxx:214
 TMapFile.cxx:215
 TMapFile.cxx:216
 TMapFile.cxx:217
 TMapFile.cxx:218
 TMapFile.cxx:219
 TMapFile.cxx:220
 TMapFile.cxx:221
 TMapFile.cxx:222
 TMapFile.cxx:223
 TMapFile.cxx:224
 TMapFile.cxx:225
 TMapFile.cxx:226
 TMapFile.cxx:227
 TMapFile.cxx:228
 TMapFile.cxx:229
 TMapFile.cxx:230
 TMapFile.cxx:231
 TMapFile.cxx:232
 TMapFile.cxx:233
 TMapFile.cxx:234
 TMapFile.cxx:235
 TMapFile.cxx:236
 TMapFile.cxx:237
 TMapFile.cxx:238
 TMapFile.cxx:239
 TMapFile.cxx:240
 TMapFile.cxx:241
 TMapFile.cxx:242
 TMapFile.cxx:243
 TMapFile.cxx:244
 TMapFile.cxx:245
 TMapFile.cxx:246
 TMapFile.cxx:247
 TMapFile.cxx:248
 TMapFile.cxx:249
 TMapFile.cxx:250
 TMapFile.cxx:251
 TMapFile.cxx:252
 TMapFile.cxx:253
 TMapFile.cxx:254
 TMapFile.cxx:255
 TMapFile.cxx:256
 TMapFile.cxx:257
 TMapFile.cxx:258
 TMapFile.cxx:259
 TMapFile.cxx:260
 TMapFile.cxx:261
 TMapFile.cxx:262
 TMapFile.cxx:263
 TMapFile.cxx:264
 TMapFile.cxx:265
 TMapFile.cxx:266
 TMapFile.cxx:267
 TMapFile.cxx:268
 TMapFile.cxx:269
 TMapFile.cxx:270
 TMapFile.cxx:271
 TMapFile.cxx:272
 TMapFile.cxx:273
 TMapFile.cxx:274
 TMapFile.cxx:275
 TMapFile.cxx:276
 TMapFile.cxx:277
 TMapFile.cxx:278
 TMapFile.cxx:279
 TMapFile.cxx:280
 TMapFile.cxx:281
 TMapFile.cxx:282
 TMapFile.cxx:283
 TMapFile.cxx:284
 TMapFile.cxx:285
 TMapFile.cxx:286
 TMapFile.cxx:287
 TMapFile.cxx:288
 TMapFile.cxx:289
 TMapFile.cxx:290
 TMapFile.cxx:291
 TMapFile.cxx:292
 TMapFile.cxx:293
 TMapFile.cxx:294
 TMapFile.cxx:295
 TMapFile.cxx:296
 TMapFile.cxx:297
 TMapFile.cxx:298
 TMapFile.cxx:299
 TMapFile.cxx:300
 TMapFile.cxx:301
 TMapFile.cxx:302
 TMapFile.cxx:303
 TMapFile.cxx:304
 TMapFile.cxx:305
 TMapFile.cxx:306
 TMapFile.cxx:307
 TMapFile.cxx:308
 TMapFile.cxx:309
 TMapFile.cxx:310
 TMapFile.cxx:311
 TMapFile.cxx:312
 TMapFile.cxx:313
 TMapFile.cxx:314
 TMapFile.cxx:315
 TMapFile.cxx:316
 TMapFile.cxx:317
 TMapFile.cxx:318
 TMapFile.cxx:319
 TMapFile.cxx:320
 TMapFile.cxx:321
 TMapFile.cxx:322
 TMapFile.cxx:323
 TMapFile.cxx:324
 TMapFile.cxx:325
 TMapFile.cxx:326
 TMapFile.cxx:327
 TMapFile.cxx:328
 TMapFile.cxx:329
 TMapFile.cxx:330
 TMapFile.cxx:331
 TMapFile.cxx:332
 TMapFile.cxx:333
 TMapFile.cxx:334
 TMapFile.cxx:335
 TMapFile.cxx:336
 TMapFile.cxx:337
 TMapFile.cxx:338
 TMapFile.cxx:339
 TMapFile.cxx:340
 TMapFile.cxx:341
 TMapFile.cxx:342
 TMapFile.cxx:343
 TMapFile.cxx:344
 TMapFile.cxx:345
 TMapFile.cxx:346
 TMapFile.cxx:347
 TMapFile.cxx:348
 TMapFile.cxx:349
 TMapFile.cxx:350
 TMapFile.cxx:351
 TMapFile.cxx:352
 TMapFile.cxx:353
 TMapFile.cxx:354
 TMapFile.cxx:355
 TMapFile.cxx:356
 TMapFile.cxx:357
 TMapFile.cxx:358
 TMapFile.cxx:359
 TMapFile.cxx:360
 TMapFile.cxx:361
 TMapFile.cxx:362
 TMapFile.cxx:363
 TMapFile.cxx:364
 TMapFile.cxx:365
 TMapFile.cxx:366
 TMapFile.cxx:367
 TMapFile.cxx:368
 TMapFile.cxx:369
 TMapFile.cxx:370
 TMapFile.cxx:371
 TMapFile.cxx:372
 TMapFile.cxx:373
 TMapFile.cxx:374
 TMapFile.cxx:375
 TMapFile.cxx:376
 TMapFile.cxx:377
 TMapFile.cxx:378
 TMapFile.cxx:379
 TMapFile.cxx:380
 TMapFile.cxx:381
 TMapFile.cxx:382
 TMapFile.cxx:383
 TMapFile.cxx:384
 TMapFile.cxx:385
 TMapFile.cxx:386
 TMapFile.cxx:387
 TMapFile.cxx:388
 TMapFile.cxx:389
 TMapFile.cxx:390
 TMapFile.cxx:391
 TMapFile.cxx:392
 TMapFile.cxx:393
 TMapFile.cxx:394
 TMapFile.cxx:395
 TMapFile.cxx:396
 TMapFile.cxx:397
 TMapFile.cxx:398
 TMapFile.cxx:399
 TMapFile.cxx:400
 TMapFile.cxx:401
 TMapFile.cxx:402
 TMapFile.cxx:403
 TMapFile.cxx:404
 TMapFile.cxx:405
 TMapFile.cxx:406
 TMapFile.cxx:407
 TMapFile.cxx:408
 TMapFile.cxx:409
 TMapFile.cxx:410
 TMapFile.cxx:411
 TMapFile.cxx:412
 TMapFile.cxx:413
 TMapFile.cxx:414
 TMapFile.cxx:415
 TMapFile.cxx:416
 TMapFile.cxx:417
 TMapFile.cxx:418
 TMapFile.cxx:419
 TMapFile.cxx:420
 TMapFile.cxx:421
 TMapFile.cxx:422
 TMapFile.cxx:423
 TMapFile.cxx:424
 TMapFile.cxx:425
 TMapFile.cxx:426
 TMapFile.cxx:427
 TMapFile.cxx:428
 TMapFile.cxx:429
 TMapFile.cxx:430
 TMapFile.cxx:431
 TMapFile.cxx:432
 TMapFile.cxx:433
 TMapFile.cxx:434
 TMapFile.cxx:435
 TMapFile.cxx:436
 TMapFile.cxx:437
 TMapFile.cxx:438
 TMapFile.cxx:439
 TMapFile.cxx:440
 TMapFile.cxx:441
 TMapFile.cxx:442
 TMapFile.cxx:443
 TMapFile.cxx:444
 TMapFile.cxx:445
 TMapFile.cxx:446
 TMapFile.cxx:447
 TMapFile.cxx:448
 TMapFile.cxx:449
 TMapFile.cxx:450
 TMapFile.cxx:451
 TMapFile.cxx:452
 TMapFile.cxx:453
 TMapFile.cxx:454
 TMapFile.cxx:455
 TMapFile.cxx:456
 TMapFile.cxx:457
 TMapFile.cxx:458
 TMapFile.cxx:459
 TMapFile.cxx:460
 TMapFile.cxx:461
 TMapFile.cxx:462
 TMapFile.cxx:463
 TMapFile.cxx:464
 TMapFile.cxx:465
 TMapFile.cxx:466
 TMapFile.cxx:467
 TMapFile.cxx:468
 TMapFile.cxx:469
 TMapFile.cxx:470
 TMapFile.cxx:471
 TMapFile.cxx:472
 TMapFile.cxx:473
 TMapFile.cxx:474
 TMapFile.cxx:475
 TMapFile.cxx:476
 TMapFile.cxx:477
 TMapFile.cxx:478
 TMapFile.cxx:479
 TMapFile.cxx:480
 TMapFile.cxx:481
 TMapFile.cxx:482
 TMapFile.cxx:483
 TMapFile.cxx:484
 TMapFile.cxx:485
 TMapFile.cxx:486
 TMapFile.cxx:487
 TMapFile.cxx:488
 TMapFile.cxx:489
 TMapFile.cxx:490
 TMapFile.cxx:491
 TMapFile.cxx:492
 TMapFile.cxx:493
 TMapFile.cxx:494
 TMapFile.cxx:495
 TMapFile.cxx:496
 TMapFile.cxx:497
 TMapFile.cxx:498
 TMapFile.cxx:499
 TMapFile.cxx:500
 TMapFile.cxx:501
 TMapFile.cxx:502
 TMapFile.cxx:503
 TMapFile.cxx:504
 TMapFile.cxx:505
 TMapFile.cxx:506
 TMapFile.cxx:507
 TMapFile.cxx:508
 TMapFile.cxx:509
 TMapFile.cxx:510
 TMapFile.cxx:511
 TMapFile.cxx:512
 TMapFile.cxx:513
 TMapFile.cxx:514
 TMapFile.cxx:515
 TMapFile.cxx:516
 TMapFile.cxx:517
 TMapFile.cxx:518
 TMapFile.cxx:519
 TMapFile.cxx:520
 TMapFile.cxx:521
 TMapFile.cxx:522
 TMapFile.cxx:523
 TMapFile.cxx:524
 TMapFile.cxx:525
 TMapFile.cxx:526
 TMapFile.cxx:527
 TMapFile.cxx:528
 TMapFile.cxx:529
 TMapFile.cxx:530
 TMapFile.cxx:531
 TMapFile.cxx:532
 TMapFile.cxx:533
 TMapFile.cxx:534
 TMapFile.cxx:535
 TMapFile.cxx:536
 TMapFile.cxx:537
 TMapFile.cxx:538
 TMapFile.cxx:539
 TMapFile.cxx:540
 TMapFile.cxx:541
 TMapFile.cxx:542
 TMapFile.cxx:543
 TMapFile.cxx:544
 TMapFile.cxx:545
 TMapFile.cxx:546
 TMapFile.cxx:547
 TMapFile.cxx:548
 TMapFile.cxx:549
 TMapFile.cxx:550
 TMapFile.cxx:551
 TMapFile.cxx:552
 TMapFile.cxx:553
 TMapFile.cxx:554
 TMapFile.cxx:555
 TMapFile.cxx:556
 TMapFile.cxx:557
 TMapFile.cxx:558
 TMapFile.cxx:559
 TMapFile.cxx:560
 TMapFile.cxx:561
 TMapFile.cxx:562
 TMapFile.cxx:563
 TMapFile.cxx:564
 TMapFile.cxx:565
 TMapFile.cxx:566
 TMapFile.cxx:567
 TMapFile.cxx:568
 TMapFile.cxx:569
 TMapFile.cxx:570
 TMapFile.cxx:571
 TMapFile.cxx:572
 TMapFile.cxx:573
 TMapFile.cxx:574
 TMapFile.cxx:575
 TMapFile.cxx:576
 TMapFile.cxx:577
 TMapFile.cxx:578
 TMapFile.cxx:579
 TMapFile.cxx:580
 TMapFile.cxx:581
 TMapFile.cxx:582
 TMapFile.cxx:583
 TMapFile.cxx:584
 TMapFile.cxx:585
 TMapFile.cxx:586
 TMapFile.cxx:587
 TMapFile.cxx:588
 TMapFile.cxx:589
 TMapFile.cxx:590
 TMapFile.cxx:591
 TMapFile.cxx:592
 TMapFile.cxx:593
 TMapFile.cxx:594
 TMapFile.cxx:595
 TMapFile.cxx:596
 TMapFile.cxx:597
 TMapFile.cxx:598
 TMapFile.cxx:599
 TMapFile.cxx:600
 TMapFile.cxx:601
 TMapFile.cxx:602
 TMapFile.cxx:603
 TMapFile.cxx:604
 TMapFile.cxx:605
 TMapFile.cxx:606
 TMapFile.cxx:607
 TMapFile.cxx:608
 TMapFile.cxx:609
 TMapFile.cxx:610
 TMapFile.cxx:611
 TMapFile.cxx:612
 TMapFile.cxx:613
 TMapFile.cxx:614
 TMapFile.cxx:615
 TMapFile.cxx:616
 TMapFile.cxx:617
 TMapFile.cxx:618
 TMapFile.cxx:619
 TMapFile.cxx:620
 TMapFile.cxx:621
 TMapFile.cxx:622
 TMapFile.cxx:623
 TMapFile.cxx:624
 TMapFile.cxx:625
 TMapFile.cxx:626
 TMapFile.cxx:627
 TMapFile.cxx:628
 TMapFile.cxx:629
 TMapFile.cxx:630
 TMapFile.cxx:631
 TMapFile.cxx:632
 TMapFile.cxx:633
 TMapFile.cxx:634
 TMapFile.cxx:635
 TMapFile.cxx:636
 TMapFile.cxx:637
 TMapFile.cxx:638
 TMapFile.cxx:639
 TMapFile.cxx:640
 TMapFile.cxx:641
 TMapFile.cxx:642
 TMapFile.cxx:643
 TMapFile.cxx:644
 TMapFile.cxx:645
 TMapFile.cxx:646
 TMapFile.cxx:647
 TMapFile.cxx:648
 TMapFile.cxx:649
 TMapFile.cxx:650
 TMapFile.cxx:651
 TMapFile.cxx:652
 TMapFile.cxx:653
 TMapFile.cxx:654
 TMapFile.cxx:655
 TMapFile.cxx:656
 TMapFile.cxx:657
 TMapFile.cxx:658
 TMapFile.cxx:659
 TMapFile.cxx:660
 TMapFile.cxx:661
 TMapFile.cxx:662
 TMapFile.cxx:663
 TMapFile.cxx:664
 TMapFile.cxx:665
 TMapFile.cxx:666
 TMapFile.cxx:667
 TMapFile.cxx:668
 TMapFile.cxx:669
 TMapFile.cxx:670
 TMapFile.cxx:671
 TMapFile.cxx:672
 TMapFile.cxx:673
 TMapFile.cxx:674
 TMapFile.cxx:675
 TMapFile.cxx:676
 TMapFile.cxx:677
 TMapFile.cxx:678
 TMapFile.cxx:679
 TMapFile.cxx:680
 TMapFile.cxx:681
 TMapFile.cxx:682
 TMapFile.cxx:683
 TMapFile.cxx:684
 TMapFile.cxx:685
 TMapFile.cxx:686
 TMapFile.cxx:687
 TMapFile.cxx:688
 TMapFile.cxx:689
 TMapFile.cxx:690
 TMapFile.cxx:691
 TMapFile.cxx:692
 TMapFile.cxx:693
 TMapFile.cxx:694
 TMapFile.cxx:695
 TMapFile.cxx:696
 TMapFile.cxx:697
 TMapFile.cxx:698
 TMapFile.cxx:699
 TMapFile.cxx:700
 TMapFile.cxx:701
 TMapFile.cxx:702
 TMapFile.cxx:703
 TMapFile.cxx:704
 TMapFile.cxx:705
 TMapFile.cxx:706
 TMapFile.cxx:707
 TMapFile.cxx:708
 TMapFile.cxx:709
 TMapFile.cxx:710
 TMapFile.cxx:711
 TMapFile.cxx:712
 TMapFile.cxx:713
 TMapFile.cxx:714
 TMapFile.cxx:715
 TMapFile.cxx:716
 TMapFile.cxx:717
 TMapFile.cxx:718
 TMapFile.cxx:719
 TMapFile.cxx:720
 TMapFile.cxx:721
 TMapFile.cxx:722
 TMapFile.cxx:723
 TMapFile.cxx:724
 TMapFile.cxx:725
 TMapFile.cxx:726
 TMapFile.cxx:727
 TMapFile.cxx:728
 TMapFile.cxx:729
 TMapFile.cxx:730
 TMapFile.cxx:731
 TMapFile.cxx:732
 TMapFile.cxx:733
 TMapFile.cxx:734
 TMapFile.cxx:735
 TMapFile.cxx:736
 TMapFile.cxx:737
 TMapFile.cxx:738
 TMapFile.cxx:739
 TMapFile.cxx:740
 TMapFile.cxx:741
 TMapFile.cxx:742
 TMapFile.cxx:743
 TMapFile.cxx:744
 TMapFile.cxx:745
 TMapFile.cxx:746
 TMapFile.cxx:747
 TMapFile.cxx:748
 TMapFile.cxx:749
 TMapFile.cxx:750
 TMapFile.cxx:751
 TMapFile.cxx:752
 TMapFile.cxx:753
 TMapFile.cxx:754
 TMapFile.cxx:755
 TMapFile.cxx:756
 TMapFile.cxx:757
 TMapFile.cxx:758
 TMapFile.cxx:759
 TMapFile.cxx:760
 TMapFile.cxx:761
 TMapFile.cxx:762
 TMapFile.cxx:763
 TMapFile.cxx:764
 TMapFile.cxx:765
 TMapFile.cxx:766
 TMapFile.cxx:767
 TMapFile.cxx:768
 TMapFile.cxx:769
 TMapFile.cxx:770
 TMapFile.cxx:771
 TMapFile.cxx:772
 TMapFile.cxx:773
 TMapFile.cxx:774
 TMapFile.cxx:775
 TMapFile.cxx:776
 TMapFile.cxx:777
 TMapFile.cxx:778
 TMapFile.cxx:779
 TMapFile.cxx:780
 TMapFile.cxx:781
 TMapFile.cxx:782
 TMapFile.cxx:783
 TMapFile.cxx:784
 TMapFile.cxx:785
 TMapFile.cxx:786
 TMapFile.cxx:787
 TMapFile.cxx:788
 TMapFile.cxx:789
 TMapFile.cxx:790
 TMapFile.cxx:791
 TMapFile.cxx:792
 TMapFile.cxx:793
 TMapFile.cxx:794
 TMapFile.cxx:795
 TMapFile.cxx:796
 TMapFile.cxx:797
 TMapFile.cxx:798
 TMapFile.cxx:799
 TMapFile.cxx:800
 TMapFile.cxx:801
 TMapFile.cxx:802
 TMapFile.cxx:803
 TMapFile.cxx:804
 TMapFile.cxx:805
 TMapFile.cxx:806
 TMapFile.cxx:807
 TMapFile.cxx:808
 TMapFile.cxx:809
 TMapFile.cxx:810
 TMapFile.cxx:811
 TMapFile.cxx:812
 TMapFile.cxx:813
 TMapFile.cxx:814
 TMapFile.cxx:815
 TMapFile.cxx:816
 TMapFile.cxx:817
 TMapFile.cxx:818
 TMapFile.cxx:819
 TMapFile.cxx:820
 TMapFile.cxx:821
 TMapFile.cxx:822
 TMapFile.cxx:823
 TMapFile.cxx:824
 TMapFile.cxx:825
 TMapFile.cxx:826
 TMapFile.cxx:827
 TMapFile.cxx:828
 TMapFile.cxx:829
 TMapFile.cxx:830
 TMapFile.cxx:831
 TMapFile.cxx:832
 TMapFile.cxx:833
 TMapFile.cxx:834
 TMapFile.cxx:835
 TMapFile.cxx:836
 TMapFile.cxx:837
 TMapFile.cxx:838
 TMapFile.cxx:839
 TMapFile.cxx:840
 TMapFile.cxx:841
 TMapFile.cxx:842
 TMapFile.cxx:843
 TMapFile.cxx:844
 TMapFile.cxx:845
 TMapFile.cxx:846
 TMapFile.cxx:847
 TMapFile.cxx:848
 TMapFile.cxx:849
 TMapFile.cxx:850
 TMapFile.cxx:851
 TMapFile.cxx:852
 TMapFile.cxx:853
 TMapFile.cxx:854
 TMapFile.cxx:855
 TMapFile.cxx:856
 TMapFile.cxx:857
 TMapFile.cxx:858
 TMapFile.cxx:859
 TMapFile.cxx:860
 TMapFile.cxx:861
 TMapFile.cxx:862
 TMapFile.cxx:863
 TMapFile.cxx:864
 TMapFile.cxx:865
 TMapFile.cxx:866
 TMapFile.cxx:867
 TMapFile.cxx:868
 TMapFile.cxx:869
 TMapFile.cxx:870
 TMapFile.cxx:871
 TMapFile.cxx:872
 TMapFile.cxx:873
 TMapFile.cxx:874
 TMapFile.cxx:875
 TMapFile.cxx:876
 TMapFile.cxx:877
 TMapFile.cxx:878
 TMapFile.cxx:879
 TMapFile.cxx:880
 TMapFile.cxx:881
 TMapFile.cxx:882
 TMapFile.cxx:883
 TMapFile.cxx:884
 TMapFile.cxx:885
 TMapFile.cxx:886
 TMapFile.cxx:887
 TMapFile.cxx:888
 TMapFile.cxx:889
 TMapFile.cxx:890
 TMapFile.cxx:891
 TMapFile.cxx:892
 TMapFile.cxx:893
 TMapFile.cxx:894
 TMapFile.cxx:895
 TMapFile.cxx:896
 TMapFile.cxx:897
 TMapFile.cxx:898
 TMapFile.cxx:899
 TMapFile.cxx:900
 TMapFile.cxx:901
 TMapFile.cxx:902
 TMapFile.cxx:903
 TMapFile.cxx:904
 TMapFile.cxx:905
 TMapFile.cxx:906
 TMapFile.cxx:907
 TMapFile.cxx:908
 TMapFile.cxx:909
 TMapFile.cxx:910
 TMapFile.cxx:911
 TMapFile.cxx:912
 TMapFile.cxx:913
 TMapFile.cxx:914
 TMapFile.cxx:915
 TMapFile.cxx:916
 TMapFile.cxx:917
 TMapFile.cxx:918
 TMapFile.cxx:919
 TMapFile.cxx:920
 TMapFile.cxx:921
 TMapFile.cxx:922
 TMapFile.cxx:923
 TMapFile.cxx:924
 TMapFile.cxx:925
 TMapFile.cxx:926
 TMapFile.cxx:927
 TMapFile.cxx:928
 TMapFile.cxx:929
 TMapFile.cxx:930
 TMapFile.cxx:931
 TMapFile.cxx:932
 TMapFile.cxx:933
 TMapFile.cxx:934
 TMapFile.cxx:935
 TMapFile.cxx:936
 TMapFile.cxx:937
 TMapFile.cxx:938
 TMapFile.cxx:939
 TMapFile.cxx:940
 TMapFile.cxx:941
 TMapFile.cxx:942
 TMapFile.cxx:943
 TMapFile.cxx:944
 TMapFile.cxx:945
 TMapFile.cxx:946
 TMapFile.cxx:947
 TMapFile.cxx:948
 TMapFile.cxx:949
 TMapFile.cxx:950
 TMapFile.cxx:951
 TMapFile.cxx:952
 TMapFile.cxx:953
 TMapFile.cxx:954
 TMapFile.cxx:955
 TMapFile.cxx:956
 TMapFile.cxx:957
 TMapFile.cxx:958
 TMapFile.cxx:959
 TMapFile.cxx:960
 TMapFile.cxx:961
 TMapFile.cxx:962
 TMapFile.cxx:963
 TMapFile.cxx:964
 TMapFile.cxx:965
 TMapFile.cxx:966
 TMapFile.cxx:967
 TMapFile.cxx:968
 TMapFile.cxx:969
 TMapFile.cxx:970
 TMapFile.cxx:971
 TMapFile.cxx:972
 TMapFile.cxx:973
 TMapFile.cxx:974
 TMapFile.cxx:975
 TMapFile.cxx:976
 TMapFile.cxx:977
 TMapFile.cxx:978
 TMapFile.cxx:979
 TMapFile.cxx:980
 TMapFile.cxx:981
 TMapFile.cxx:982
 TMapFile.cxx:983
 TMapFile.cxx:984
 TMapFile.cxx:985
 TMapFile.cxx:986
 TMapFile.cxx:987
 TMapFile.cxx:988
 TMapFile.cxx:989
 TMapFile.cxx:990
 TMapFile.cxx:991
 TMapFile.cxx:992
 TMapFile.cxx:993
 TMapFile.cxx:994
 TMapFile.cxx:995
 TMapFile.cxx:996
 TMapFile.cxx:997
 TMapFile.cxx:998
 TMapFile.cxx:999
 TMapFile.cxx:1000
 TMapFile.cxx:1001
 TMapFile.cxx:1002
 TMapFile.cxx:1003
 TMapFile.cxx:1004
 TMapFile.cxx:1005
 TMapFile.cxx:1006
 TMapFile.cxx:1007
 TMapFile.cxx:1008
 TMapFile.cxx:1009
 TMapFile.cxx:1010
 TMapFile.cxx:1011
 TMapFile.cxx:1012
 TMapFile.cxx:1013
 TMapFile.cxx:1014
 TMapFile.cxx:1015
 TMapFile.cxx:1016
 TMapFile.cxx:1017
 TMapFile.cxx:1018
 TMapFile.cxx:1019
 TMapFile.cxx:1020
 TMapFile.cxx:1021
 TMapFile.cxx:1022
 TMapFile.cxx:1023
 TMapFile.cxx:1024
 TMapFile.cxx:1025
 TMapFile.cxx:1026
 TMapFile.cxx:1027
 TMapFile.cxx:1028
 TMapFile.cxx:1029
 TMapFile.cxx:1030
 TMapFile.cxx:1031
 TMapFile.cxx:1032
 TMapFile.cxx:1033
 TMapFile.cxx:1034
 TMapFile.cxx:1035
 TMapFile.cxx:1036
 TMapFile.cxx:1037
 TMapFile.cxx:1038
 TMapFile.cxx:1039
 TMapFile.cxx:1040
 TMapFile.cxx:1041
 TMapFile.cxx:1042
 TMapFile.cxx:1043
 TMapFile.cxx:1044
 TMapFile.cxx:1045
 TMapFile.cxx:1046
 TMapFile.cxx:1047
 TMapFile.cxx:1048
 TMapFile.cxx:1049
 TMapFile.cxx:1050
 TMapFile.cxx:1051
 TMapFile.cxx:1052
 TMapFile.cxx:1053
 TMapFile.cxx:1054
 TMapFile.cxx:1055
 TMapFile.cxx:1056
 TMapFile.cxx:1057
 TMapFile.cxx:1058
 TMapFile.cxx:1059
 TMapFile.cxx:1060
 TMapFile.cxx:1061
 TMapFile.cxx:1062
 TMapFile.cxx:1063
 TMapFile.cxx:1064
 TMapFile.cxx:1065
 TMapFile.cxx:1066
 TMapFile.cxx:1067
 TMapFile.cxx:1068
 TMapFile.cxx:1069
 TMapFile.cxx:1070
 TMapFile.cxx:1071
 TMapFile.cxx:1072
 TMapFile.cxx:1073
 TMapFile.cxx:1074
 TMapFile.cxx:1075
 TMapFile.cxx:1076
 TMapFile.cxx:1077
 TMapFile.cxx:1078
 TMapFile.cxx:1079
 TMapFile.cxx:1080
 TMapFile.cxx:1081
 TMapFile.cxx:1082
 TMapFile.cxx:1083
 TMapFile.cxx:1084
 TMapFile.cxx:1085
 TMapFile.cxx:1086
 TMapFile.cxx:1087
 TMapFile.cxx:1088
 TMapFile.cxx:1089
 TMapFile.cxx:1090
 TMapFile.cxx:1091
 TMapFile.cxx:1092
 TMapFile.cxx:1093
 TMapFile.cxx:1094
 TMapFile.cxx:1095
 TMapFile.cxx:1096
 TMapFile.cxx:1097
 TMapFile.cxx:1098
 TMapFile.cxx:1099
 TMapFile.cxx:1100
 TMapFile.cxx:1101
 TMapFile.cxx:1102
 TMapFile.cxx:1103
 TMapFile.cxx:1104
 TMapFile.cxx:1105
 TMapFile.cxx:1106
 TMapFile.cxx:1107
 TMapFile.cxx:1108
 TMapFile.cxx:1109
 TMapFile.cxx:1110
 TMapFile.cxx:1111
 TMapFile.cxx:1112
 TMapFile.cxx:1113
 TMapFile.cxx:1114
 TMapFile.cxx:1115
 TMapFile.cxx:1116
 TMapFile.cxx:1117
 TMapFile.cxx:1118
 TMapFile.cxx:1119
 TMapFile.cxx:1120
 TMapFile.cxx:1121
 TMapFile.cxx:1122
 TMapFile.cxx:1123
 TMapFile.cxx:1124
 TMapFile.cxx:1125
 TMapFile.cxx:1126
 TMapFile.cxx:1127
 TMapFile.cxx:1128
 TMapFile.cxx:1129
 TMapFile.cxx:1130
 TMapFile.cxx:1131
 TMapFile.cxx:1132
 TMapFile.cxx:1133
 TMapFile.cxx:1134
 TMapFile.cxx:1135
 TMapFile.cxx:1136
 TMapFile.cxx:1137
 TMapFile.cxx:1138
 TMapFile.cxx:1139
 TMapFile.cxx:1140
 TMapFile.cxx:1141
 TMapFile.cxx:1142
 TMapFile.cxx:1143
 TMapFile.cxx:1144
 TMapFile.cxx:1145
 TMapFile.cxx:1146
 TMapFile.cxx:1147
 TMapFile.cxx:1148
 TMapFile.cxx:1149
 TMapFile.cxx:1150
 TMapFile.cxx:1151
 TMapFile.cxx:1152
 TMapFile.cxx:1153
 TMapFile.cxx:1154
 TMapFile.cxx:1155
 TMapFile.cxx:1156
 TMapFile.cxx:1157
 TMapFile.cxx:1158
 TMapFile.cxx:1159
 TMapFile.cxx:1160
 TMapFile.cxx:1161
 TMapFile.cxx:1162
 TMapFile.cxx:1163
 TMapFile.cxx:1164
 TMapFile.cxx:1165
 TMapFile.cxx:1166
 TMapFile.cxx:1167
 TMapFile.cxx:1168
 TMapFile.cxx:1169
 TMapFile.cxx:1170
 TMapFile.cxx:1171
 TMapFile.cxx:1172