#ifdef WIN32
#pragma optimize("",off)
#endif
#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__ALPHA) && !defined(R__FBSD)) || \
defined (R__SOLARIS) || defined(R__AIX) || defined(R__HIUX) || \
__GLIBC_MINOR__ > 0
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
#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;
TMapRec::TMapRec(const char *name, const TObject *obj, Int_t size, void *buf)
{
fName = StrDup(name);
fClassName = 0;
fObject = (TObject*)obj;
fBuffer = buf;
fBufSize = size;
fNext = 0;
}
TMapRec::~TMapRec()
{
delete [] fName;
delete [] fClassName;
}
TObject *TMapRec::GetObject() const
{
return fObject;
}
ClassImp(TMapFile)
TMapFile::TMapFile()
{
fFd = -1;
fMmallocDesc = 0;
fFirst = 0;
}
TMapFile::TMapFile(const char *name, const char *title, Option_t *option,
Int_t size, TMapFile *&newMapFile)
{
#ifndef WIN32
fFd = -1;
fSemaphore = -1;
#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;
}
}
if (create || update) {
#ifndef WIN32
fFd = open(fname, O_RDWR | O_CREAT, 0644);
#else
fFd = (Int_t) CreateFile(fname,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY,
(HANDLE) NULL);
#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,
GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_TEMPORARY,
(HANDLE) NULL);
#endif
if (fFd == (Int_t)INVALID_HANDLE_VALUE) {
SysError("TMapFile", "file %s can not be opened for reading", fname);
goto zombie;
}
fWritable = kFALSE;
}
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) {
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) {
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;
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;
}
fVersion = -1;
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfMappedFiles()->AddLast(this);
} else {
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;
fVersion = -1;
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfMappedFiles()->AddLast(this);
}
mapfil->InitDirectory();
{
R__LOCKGUARD2(gROOTMutex);
gROOT->GetListOfMappedFiles()->AddFirst(mapfil);
}
if (cleanup) delete [] cleanup;
newMapFile = mapfil;
return;
zombie:
MakeZombie();
newMapFile = this;
gMmallocDesc = 0;
}
TMapFile::TMapFile(const TMapFile &f, Long_t offset) : TObject(f)
{
fFd = f.fFd;
fVersion = f.fVersion;
fName = StrDup((char *)((long)f.fName + offset));
fTitle = StrDup((char *)((long)f.fTitle + offset));
fOption = StrDup((char *)((long)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);
#endif
}
TMapFile::~TMapFile()
{
if (fDirectory == gDirectory) gDirectory = gROOT;
delete fDirectory; fDirectory = 0;
if (fBrowseList) fBrowseList->Delete();
delete fBrowseList; fBrowseList = 0;
if (fVersion == -1)
return;
if (fWritable)
TObject::SetDtorOnly(this);
Close("dtor");
fgMmallocDesc = fMmallocDesc;
}
void TMapFile::InitDirectory()
{
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)
{
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)) {
}
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)
{
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);
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)
{
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)
{
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()
{
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)
{
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);
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
{
#ifdef HAVE_SEMOP
#ifndef WIN32
fSemaphore = semget(IPC_PRIVATE, 1, SEM_R|SEM_A|(SEM_R>>3)|(SEM_A>>3)|
(SEM_R>>6)|(SEM_A>>6));
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()
{
#ifdef HAVE_SEMOP
#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()
{
#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
if (fSemaphore != (Int_t)INVALID_HANDLE_VALUE)
WaitForSingleObject((HANDLE)fhSemaphore,INFINITE);
#endif
#endif
if (!fWritable && fMmallocDesc) {
if (mmalloc_update_mapping(fMmallocDesc) == -1)
Error("AcquireSemaphore", "cannot update mapping");
}
return 0;
}
Int_t TMapFile::ReleaseSemaphore()
{
#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)
{
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 (!shadow->fWritable)
fMmallocDesc = 0;
}
if (shadow->fFd != -1)
#ifndef WIN32
close(shadow->fFd);
#else
CloseHandle((HANDLE)shadow->fFd);
#endif
delete shadow;
}
TMapFile *TMapFile::FindShadowMapFile()
{
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
{
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
{
if (fMmallocDesc && fVersion > 0) return kTRUE;
return kFALSE;
}
void TMapFile::Browse(TBrowser *b)
{
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)
{
if (fDirectory)
return fDirectory->cd(path);
return kFALSE;
}
void TMapFile::ls(Option_t *) const
{
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)
{
fWritten++;
fSumBuffer += bufsize;
fSum2Buffer += bufsize*bufsize;
}
Int_t TMapFile::GetBestBuffer()
{
if (!fWritten) return TBuffer::kMinimalSize;
Double_t mean = fSumBuffer/fWritten;
Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer - mean*mean);
return (Int_t)(mean + sqrt(rms2));
}
TMapFile *TMapFile::Create(const char *name, Option_t *option, Int_t size,
const char *title)
{
TMapFile *newMapFile;
new TMapFile(name, title, option, size, newMapFile);
return newMapFile;
}
void TMapFile::SetMapAddress(Long_t addr)
{
fgMapAddress = addr;
}
void *TMapFile::MapToAddress()
{
#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)
{
mmalloc_detach(fgMmallocDesc);
fgMmallocDesc = 0;
TObject::operator delete(ptr);
}
Last change: Wed Jun 25 08:49:01 2008
Last generated: 2008-06-25 08:49
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.