Logo ROOT  
Reference Guide
TMapFile.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Fons Rademakers 08/07/97
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11#ifdef WIN32
12#pragma optimize("",off)
13#endif
14
15/**
16\class TMapFile
17\ingroup IO
18
19This class implements a shared memory region mapped to a file.
20Objects can be placed into this shared memory area using the Add()
21member function. To actually place a copy of the object is shared
22memory call Update() also whenever the mapped object(s) change(s)
23call Update() to put a fresh copy in the shared memory. This extra
24step is necessary since it is not possible to share objects with
25virtual pointers between processes (the vtbl ptr points to the
26originators unique address space and can not be used by the
27consumer process(es)). Consumer processes can map the memory region
28from this file and access the objects stored in it via the Get()
29method (which returns a copy of the object stored in the shared
30memory with correct vtbl ptr set). Only objects of classes with a
31Streamer() member function defined can be shared.
32
33I know the current implementation is not ideal (you need to copy to
34and from the shared memory file) but the main problem is with the
35class' virtual_table pointer. This pointer points to a table unique
36for every process. Therefore, different options are:
37 -# One could allocate an object directly in shared memory in the
38 producer, but the consumer still has to copy the object from
39 shared memory into a local object which has the correct vtbl
40 pointer for that process (copy ctor's can be used for creating
41 the local copy).
42 -# Another possibility is to only allow objects without virtual
43 functions in shared memory (like simple C structs), or to
44 forbid (how?) the consumer from calling any virtual functions
45 of the objects in shared memory.
46 -# A last option is to copy the object internals to shared memory
47 and copy them again from there. This is what is done in the
48 TMapFile (using the object Streamer() to make a deep copy).
49
50Option 1) saves one copy, but requires solid copy ctor's (along the
51full inheritance chain) to rebuild the object in the consumer. Most
52classes don't provide these copy ctor's, especially not when objects
53contain collections, etc. 2) is too limiting or dangerous (calling
54accidentally a virtual function will segv). So since we have a
55robust Streamer mechanism I opted for 3).
56**/
57
58
59#ifdef WIN32
60# include <windows.h>
61# include <process.h>
62# ifdef GetObject
63# undef GetObject
64# endif
65# define HAVE_SEMOP
66
67# ifdef CreateSemaphore
68# undef CreateSemaphore
69# endif
70
71# ifdef AcquireSemaphore
72# undef AcquireSemaphore;
73# endif
74
75# ifdef ReleaseSemaphore
76# undef ReleaseSemaphore
77# endif
78
79# ifdef DeleteSemaphore
80# undef DeleteSemaphore
81# endif
82
83#else
84# define INVALID_HANDLE_VALUE -1
85#endif
86
87#include <fcntl.h>
88#include <errno.h>
89
90#include "TMapFile.h"
91#include "TKeyMapFile.h"
92#include "TDirectoryFile.h"
93#include "TBrowser.h"
94#include "TStorage.h"
95#include "TString.h"
96#include "TSystem.h"
97#include "TClass.h"
98#include "TROOT.h"
99#include "TBufferFile.h"
100#include "TVirtualMutex.h"
101#include "mmprivate.h"
102
103#include <cmath>
104
105#if defined(R__UNIX) && !defined(R__MACOSX) && !defined(R__WINGCC)
106#define HAVE_SEMOP
107#include <sys/types.h>
108#include <sys/ipc.h>
109#include <sys/sem.h>
110#if defined(R__HPUX) || \
111 defined (R__SOLARIS) || defined(R__AIX) || defined(R__HIUX) || \
112 __GLIBC_MINOR__ > 0
113union semun {
114 int val; // value for SETVAL
115 struct semid_ds *buf; // buffer for IPC_STAT & IPC_SET
116 ushort *array; // array for GETALL & SETALL
117};
118#endif
119#if defined(R__LINUX) || defined(R__LYNXOS) || defined(R__HURD)
120# define SEM_A 0200 // alter permission
121# define SEM_R 0400 // read permission
122#endif
123#endif
124
125
128
129//void *ROOT::Internal::gMmallocDesc = 0; //is initialized in TStorage.cxx
130
131
132namespace {
133////////////////////////////////////////////////////////////////////////////////
134/// Delete memory and return true if memory belongs to a TMapFile.
135 static bool FreeIfTMapFile(void* ptr) {
136 if (TMapFile *mf = TMapFile::WhichMapFile(ptr)) {
137 if (mf->IsWritable())
138 ::mfree(mf->GetMmallocDesc(), ptr);
139 return true;
140 }
141 return false;
142 }
143}
144
145
146////////////////////////////////////////////////////////////////////////////////
147/// Set ROOT::Internal::gFreeIfTMapFile on library load.
148
149struct SetFreeIfTMapFile_t {
150 SetFreeIfTMapFile_t() {
151 ROOT::Internal::gFreeIfTMapFile = FreeIfTMapFile;
152 }
153 ~SetFreeIfTMapFile_t() {
155 }
157
158
159////////////////////////////////////////////////////////////////////////////////
160//// Constructor.
161
162TMapRec::TMapRec(const char *name, const TObject *obj, Int_t size, void *buf)
163{
164 fName = StrDup(name);
165 fClassName = 0;
166 fObject = (TObject*)obj;
167 fBuffer = buf;
168 fBufSize = size;
169 fNext = 0;
170}
171
172////////////////////////////////////////////////////////////////////////////////
173/// Destructor.
174
176{
177 delete [] fName;
178 delete [] fClassName;
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// This method returns a pointer to the original object.
183
184/// NOTE: this pointer is only valid in the process that produces the shared
185/// memory file. In a consumer process this pointer is illegal! Be careful.
186
188{
189 return fObject;
190}
191
192
193
194
196
197////////////////////////////////////////////////////////////////////////////////
198/// Default ctor. Does not much except setting some basic values.
199
201{
202 fFd = -1;
203 fVersion = 0;
204 fName = nullptr;
205 fTitle = nullptr;
206 fOption = nullptr;
207 fMmallocDesc = nullptr;
208 fBaseAddr = 0;
209 fSize = 0;
210 fFirst = nullptr;
211 fLast = nullptr;
212 fOffset = 0;
213 fDirectory = nullptr;
214 fBrowseList = nullptr;
216 fSemaphore = -1;
217 fhSemaphore = 0;
218 fGetting = nullptr;
219 fWritten = 0;
220 fSumBuffer = 0;
221 fSum2Buffer = 0;
222}
223
224////////////////////////////////////////////////////////////////////////////////
225/// Create a memory mapped file.
226///
227/// This opens a file (to which the
228/// memory will be mapped) and attaches a memory region to it.
229/// Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE" or
230/// "READ" (see TFile). The default open mode is "READ". The size
231/// argument specifies the maximum size of shared memory file in bytes.
232/// This protected ctor is called via the static Create() method.
233
234TMapFile::TMapFile(const char *name, const char *title, Option_t *option,
235 Int_t size, TMapFile *&newMapFile)
236{
237#ifndef WIN32
238 fFd = -1;
239 fSemaphore = -1;
240 fhSemaphore = 0;
241#else
244#endif
245 fMmallocDesc = nullptr;
246 fSize = size;
247 fFirst = 0;
248 fOffset = 0;
249 fVersion = gROOT->GetVersionInt();
250 fTitle = StrDup(title);
251 fOption = StrDup(option);
252 fDirectory = nullptr;
253 fBrowseList = nullptr;
254 fGetting = nullptr;
255 fWritten = 0;
256 fSumBuffer = 0;
257 fSum2Buffer = 0;
258
259 char *cleanup = nullptr;
260 Bool_t create = kFALSE;
261 Bool_t recreate, update, read;
262
263 {
264 TString opt = option;
265
266 if (!opt.CompareTo("NEW", TString::kIgnoreCase) ||
267 !opt.CompareTo("CREATE", TString::kIgnoreCase))
268 create = kTRUE;
269 recreate = opt.CompareTo("RECREATE", TString::kIgnoreCase)
270 ? kFALSE : kTRUE;
271 update = opt.CompareTo("UPDATE", TString::kIgnoreCase)
272 ? kFALSE : kTRUE;
273 read = opt.CompareTo("READ", TString::kIgnoreCase)
274 ? kFALSE : kTRUE;
275 if (!create && !recreate && !update && !read) {
276 read = kTRUE;
277 delete [] fOption;
278 fOption = StrDup("READ");
279 }
280 }
281
282 const char *fname;
283 if ((fName = gSystem->ExpandPathName(name))) {
284 fname = fName;
285 } else {
286 Error("TMapFile", "error expanding path %s", name);
287 goto zombie;
288 }
289
290 if (recreate) {
291 if (!gSystem->AccessPathName(fname, kFileExists))
292 gSystem->Unlink(fname);
293 recreate = kFALSE;
294 create = kTRUE;
295 delete [] fOption;
296 fOption = StrDup("CREATE");
297 }
298 if (create && !gSystem->AccessPathName(fname, kFileExists)) {
299 Error("TMapFile", "file %s already exists", fname);
300 goto zombie;
301 }
302 if (update) {
303 if (gSystem->AccessPathName(fname, kFileExists)) {
304 update = kFALSE;
305 create = kTRUE;
306 }
308 Error("TMapFile", "no write permission, could not open file %s", fname);
309 goto zombie;
310 }
311 }
312 if (read) {
313 if (gSystem->AccessPathName(fname, kFileExists)) {
314 Error("TMapFile", "file %s does not exist", fname);
315 goto zombie;
316 }
318 Error("TMapFile", "no read permission, could not open file %s", fname);
319 goto zombie;
320 }
321 }
322
323 // Open file to which memory will be mapped
324 if (create || update) {
325#ifndef WIN32
326 fFd = open(fname, O_RDWR | O_CREAT, 0644);
327#else
328 fFd = (Int_t) CreateFile(fname, // pointer to name of the file
329 GENERIC_WRITE | GENERIC_READ, // access (read-write) mode
330 FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
331 NULL, // pointer to security attributes
332 OPEN_ALWAYS, // how to create
333 FILE_ATTRIBUTE_TEMPORARY, // file attributes
334 (HANDLE) NULL); // handle to file with attributes to copy
335#endif
337 SysError("TMapFile", "file %s can not be opened", fname);
338 goto zombie;
339 }
341 } else {
342#ifndef WIN32
343 fFd = open(fname, O_RDONLY);
344#else
345 fFd = (Int_t) CreateFile(fname, // pointer to name of the file
346 GENERIC_READ, // access (read-write) mode
347 FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
348 NULL, // pointer to security attributes
349 OPEN_EXISTING, // how to create
350 FILE_ATTRIBUTE_TEMPORARY, // file attributes
351 (HANDLE) NULL); // handle to file with attributes to copy
352#endif
354 SysError("TMapFile", "file %s can not be opened for reading", fname);
355 goto zombie;
356 }
358 }
359
360 // Attach memory region to file.
361 void *mapto;
362 TMapFile *mapfil;
363
364 if (((mapto = MapToAddress()) == (void *)-1) ||
365#ifndef WIN32
366 ((fMmallocDesc = mmalloc_attach(fFd, mapto, fSize)) == 0)) {
367#else
368 ((fMmallocDesc = mmalloc_attach((HANDLE) fFd, mapto, fSize)) == 0)) {
369#endif
370
371 if (mapto == (void *)-1) {
372 Error("TMapFile", "no memory mapped file capability available\n"
373 "Use rootn.exe or link application against \"-lNew\"");
374 } else {
375 if (fMmallocDesc == 0 && fWritable)
376 Error("TMapFile", "mapped file not in mmalloc format or\n"
377 "already open in RW mode by another process");
378 if (fMmallocDesc == 0 && !fWritable)
379 Error("TMapFile", "mapped file not in mmalloc format");
380 }
381#ifndef WIN32
382 close(fFd);
383#else
384 CloseHandle((HANDLE) fFd);
385#endif
386 fFd = -1;
387 if (create)
388 gSystem->Unlink(fname);
389 goto zombie;
390
391 } else if ((mapfil = (TMapFile *) mmalloc_getkey(fMmallocDesc, 0)) != 0) {
392
393 // File contains mmalloc heap. If we are in write mode and mapped
394 // file already connected in write mode switch to read-only mode.
395 // Check if ROOT versions are compatible.
396 // If so update mapped version of TMapFile to reflect current
397 // situation (only if not opened in READ mode).
398 if (mapfil->fVersion != fVersion) {
399 Error("TMapFile", "map file %s (%d) incompatible with current ROOT version (%d)",
400 fname, mapfil->fVersion, fVersion);
401 mmalloc_detach(fMmallocDesc);
402#ifndef WIN32
403 close(fFd);
404#else
405 CloseHandle((HANDLE) fFd);
406#endif
407 fFd = -1;
408 fMmallocDesc = 0;
409 goto zombie;
410 }
411
412 if (mapfil->fWritable && fWritable) {
413 Warning("TMapFile", "map file already open in write mode, opening in read-only mode");
415 }
416
417 fBaseAddr = mapfil->fBaseAddr;
418 fSize = mapfil->fSize;
419
420 if (fWritable) {
421 // create new TMapFile object in mapped heap to get correct vtbl ptr
424 TMapFile *mf = new TMapFile(*mapfil);
425 mf->fFd = fFd;
426 mf->fWritable = kTRUE;
427 cleanup = mf->fOption;
428 mf->fOption = StrDup(fOption);
430#ifdef WIN32
432#endif
433 mmalloc_setkey(fMmallocDesc, 0, mf);
435 mapfil = mf;
436 } else {
437 ROOT::Internal::gMmallocDesc = 0; // make sure we are in sbrk heap
438 fOffset = ((struct mdesc *) fMmallocDesc)->offset;
439 TMapFile *mf = new TMapFile(*mapfil, fOffset);
440 delete [] mf->fOption;
441 mf->fFd = fFd;
442 mf->fOption = StrDup("READ");
444 mf->fWritable = kFALSE;
445 mapfil = mf;
446 }
447
448 // store shadow mapfile (it contains the real fFd in case map
449 // is not writable)
450 fVersion = -1; // make this the shadow map file
452 gROOT->GetListOfMappedFiles()->AddLast(this);
453
454 } else {
455
456 // New file. If the file is writable create a new copy of the
457 // TMapFile which will now be allocated on the memory mapped heap.
458 if (!fWritable) {
459 Error("TMapFile", "map file is not writable");
460 mmalloc_detach(fMmallocDesc);
461#ifndef WIN32
462 close(fFd);
463#else
464 CloseHandle((HANDLE) fFd);
465#endif
466 fFd = -1;
467 fMmallocDesc = 0;
468 goto zombie;
469 }
470
471 fBaseAddr = (ULong_t)((struct mdesc *) fMmallocDesc)->base;
472
474
476
477 mapfil = new TMapFile(*this);
478 mmalloc_setkey(fMmallocDesc, 0, mapfil);
479
481
482 // store shadow mapfile
483 fVersion = -1; // make this the shadow map file
485 gROOT->GetListOfMappedFiles()->AddLast(this);
486
487 }
488
489 mapfil->InitDirectory();
490 {
492 gROOT->GetListOfMappedFiles()->AddFirst(mapfil);
493 }
494
495 if (cleanup) delete [] cleanup;
496
497 newMapFile = mapfil;
498
499 return;
500
501zombie:
502 // error in file opening occured, make this object a zombie
503 MakeZombie();
504 newMapFile = this;
506}
507
508////////////////////////////////////////////////////////////////////////////////
509/// Private copy ctor.
510///
511/// Used by the the ctor to create a new version
512/// of TMapFile in the memory mapped heap. It's main purpose is to
513/// correctly create the string data members.
514
516{
517 fFd = f.fFd;
518 fVersion = f.fVersion;
519 fName = StrDup((char *)((Long_t)f.fName + offset));
520 fTitle = StrDup((char *)((Long_t)f.fTitle + offset));
521 fOption = StrDup((char *)((Long_t)f.fOption + offset));
522 fMmallocDesc = f.fMmallocDesc;
523 fBaseAddr = f.fBaseAddr;
524 fSize = f.fSize;
525 fFirst = f.fFirst;
526 fLast = f.fLast;
527 fWritable = f.fWritable;
528 fSemaphore = f.fSemaphore;
529 fOffset = offset;
530 fDirectory = nullptr;
531 fBrowseList = nullptr;
532 fGetting = nullptr;
533 fWritten = f.fWritten;
534 fSumBuffer = f.fSumBuffer;
535 fSum2Buffer = f.fSum2Buffer;
536#ifdef WIN32
538#else
539 fhSemaphore = f.fhSemaphore;
540#endif
541}
542
543////////////////////////////////////////////////////////////////////////////////
544/// TMapFiles may not be deleted, since we want to keep the complete
545/// TMapFile object in the mapped file for later re-use. To enforce this
546/// the delete operator has been made private. Use Close() to properly
547/// terminate a TMapFile (also done via the TROOT dtor).
548
550{
552 delete fDirectory; fDirectory = nullptr;
553 if (fBrowseList) {
555 delete fBrowseList;
556 fBrowseList = nullptr;
557 }
558
559
560 // if shadow map file we are done here
561 if (fVersion == -1)
562 return;
563
564 // Writable mapfile is allocated in mapped memory. This object should
565 // not be deleted by ::operator delete(), because it is needed if we
566 // want to connect later to the file again.
567 if (fWritable)
569
570 Close("dtor");
571
573
574 delete [] fName; fName = nullptr;
575 delete [] fOption; fOption = nullptr;
576 delete [] fTitle; fTitle = nullptr;
577}
578
579////////////////////////////////////////////////////////////////////////////////
580/// Create the directory associated to this mapfile
581
583{
584 gDirectory = nullptr;
588 fDirectory->Build();
589 fDirectory->SetMother(this);
591}
592
593////////////////////////////////////////////////////////////////////////////////
594/// Add an object to the list of objects to be stored in shared memory.
595/// To place the object actually into shared memory call Update().
596
597void TMapFile::Add(const TObject *obj, const char *name)
598{
599 if (!fWritable || !fMmallocDesc) return;
600
601 Bool_t lock = fGetting != obj ? kTRUE : kFALSE;
602
603 if (lock)
605
607
608 const char *n;
609 if (name && *name)
610 n = name;
611 else
612 n = obj->GetName();
613
614 if (Remove(n, kFALSE)) {
615 //Warning("Add", "replaced object with same name %s", n);
616 }
617
618 TMapRec *mr = new TMapRec(n, obj, 0, 0);
619 if (!fFirst) {
620 fFirst = mr;
621 fLast = mr;
622 } else {
623 fLast->fNext = mr;
624 fLast = mr;
625 }
626
628
629 if (lock)
631}
632
633////////////////////////////////////////////////////////////////////////////////
634/// Update an object (or all objects, if obj == 0) in shared memory.
635
637{
638 if (!fWritable || !fMmallocDesc) return;
639
641
643
644 Bool_t all = (obj == 0) ? kTRUE : kFALSE;
645
646 TMapRec *mr = fFirst;
647 while (mr) {
648 if (all || mr->fObject == obj) {
649 TBufferFile *b;
650 if (!mr->fBufSize) {
652 mr->fClassName = StrDup(mr->fObject->ClassName());
653 } else
655 b->MapObject(mr->fObject); //register obj in map to handle self reference
656 mr->fObject->Streamer(*b);
657 mr->fBufSize = b->BufferSize();
658 mr->fBuffer = b->Buffer();
659 SumBuffer(b->Length());
660 b->DetachBuffer();
661 delete b;
662 }
663 mr = mr->fNext;
664 }
665
667
669}
670
671////////////////////////////////////////////////////////////////////////////////
672/// Remove object from shared memory.
673///
674/// Returns pointer to removed object if successful, 0 otherwise.
675
677{
678 if (!fWritable || !fMmallocDesc) return 0;
679
680 if (lock)
682
683 TObject *retObj = 0;
684 TMapRec *prev = 0, *mr = fFirst;
685 while (mr) {
686 if (mr->fObject == obj) {
687 if (mr == fFirst) {
688 fFirst = mr->fNext;
689 if (mr == fLast)
690 fLast = 0;
691 } else {
692 prev->fNext = mr->fNext;
693 if (mr == fLast)
694 fLast = prev;
695 }
696 retObj = obj;
697 delete mr;
698 break;
699 }
700 prev = mr;
701 mr = mr->fNext;
702 }
703
704 if (lock)
706
707 return retObj;
708}
709
710////////////////////////////////////////////////////////////////////////////////
711/// Remove object by name from shared memory.
712///
713/// Returns pointer to removed object if successful, 0 otherwise.
714
716{
717 if (!fWritable || !fMmallocDesc) return 0;
718
719 if (lock)
721
722 TObject *retObj = 0;
723 TMapRec *prev = 0, *mr = fFirst;
724 while (mr) {
725 if (!strcmp(mr->fName, name)) {
726 if (mr == fFirst) {
727 fFirst = mr->fNext;
728 if (mr == fLast)
729 fLast = 0;
730 } else {
731 prev->fNext = mr->fNext;
732 if (mr == fLast)
733 fLast = prev;
734 }
735 retObj = mr->fObject;
736 delete mr;
737 break;
738 }
739 prev = mr;
740 mr = mr->fNext;
741 }
742
743 if (lock)
745
746 return retObj;
747}
748
749////////////////////////////////////////////////////////////////////////////////
750/// Remove all objects from shared memory.
751
753{
754 if (!fWritable || !fMmallocDesc) return;
755
757
758 TMapRec *mr = fFirst;
759 while (mr) {
760 TMapRec *t = mr;
761 mr = mr->fNext;
762 delete t;
763 }
764 fFirst = fLast = 0;
765
767}
768
769////////////////////////////////////////////////////////////////////////////////
770/// Return pointer to object retrieved from shared memory.
771///
772/// The object must
773/// be deleted after use. If delObj is a pointer to a previously allocated
774/// object it will be deleted. Returns 0 in case object with the given
775/// name does not exist.
776
777TObject *TMapFile::Get(const char *name, TObject *delObj)
778{
779 if (!fMmallocDesc) return 0;
780
782
783 delete delObj;
784
785 TObject *obj = 0;
786 TMapRec *mr = GetFirst();
787 while (OrgAddress(mr)) {
788 if (!strcmp(mr->GetName(fOffset), name)) {
789 if (!mr->fBufSize) goto release;
791 if (!cl) {
792 Error("Get", "unknown class %s", mr->GetClassName(fOffset));
793 goto release;
794 }
795
796 obj = (TObject *)cl->New();
797 if (!obj) {
798 Error("Get", "cannot create new object of class %s", mr->GetClassName(fOffset));
799 goto release;
800 }
801
802 fGetting = obj;
804 b->MapObject(obj); //register obj in map to handle self reference
805 obj->Streamer(*b);
806 b->DetachBuffer();
807 delete b;
808 fGetting = 0;
809 goto release;
810 }
811 mr = mr->GetNext(fOffset);
812 }
813
814release:
816
817 return obj;
818}
819
820////////////////////////////////////////////////////////////////////////////////
821/// Create semaphore used for synchronizing access to shared memory.
822
823#ifndef WIN32
825#else
826void TMapFile::CreateSemaphore(int pid)
827#endif
828{
829#ifdef HAVE_SEMOP
830#ifndef WIN32
831 // create semaphore to synchronize access (should use read/write lock)
832 fSemaphore = semget(IPC_PRIVATE, 1, SEM_R|SEM_A|(SEM_R>>3)|(SEM_A>>3)|
833 (SEM_R>>6)|(SEM_A>>6));
834
835 // set semaphore to 1
836 if (fSemaphore != -1) {
837 union semun set;
838 set.val = 1;
839 semctl(fSemaphore, 0, SETVAL, set);
840 }
841#else
842 char buffer[] ="ROOT_Semaphore_xxxxxxxx";
843 int lbuf = strlen(buffer);
844 if (!pid) fSemaphore = getpid();
845 fhSemaphore = (ULong_t)CreateMutex(NULL,FALSE,itoa(fSemaphore,&buffer[lbuf-8],16));
846 if (fhSemaphore == 0) fSemaphore = (Int_t)INVALID_HANDLE_VALUE;
847#endif
848#endif
849}
850
851////////////////////////////////////////////////////////////////////////////////
852/// Delete the semaphore.
853
855{
856#ifdef HAVE_SEMOP
857 // remove semaphore
858#ifndef WIN32
859 if (fSemaphore != -1) {
860 int semid = fSemaphore;
861 fSemaphore = -1;
862 union semun set;
863 set.val = 0;
864 semctl(semid, 0, IPC_RMID, set);
865 }
866#else
868 CloseHandle((HANDLE)fhSemaphore);
869 fhSemaphore = 0;
871 }
872#endif
873#endif
874}
875
876////////////////////////////////////////////////////////////////////////////////
877/// Acquire semaphore. Returns 0 if OK, -1 on error.
878
880{
881#ifdef HAVE_SEMOP
882#ifndef WIN32
883 if (fSemaphore != -1) {
884 struct sembuf buf = { 0, -1, SEM_UNDO };
885 int intr = 0;
886again:
887 if (semop(fSemaphore, &buf, 1) == -1) {
888#if defined(R__FBSD) || defined(R__OBSD)
889 if (TSystem::GetErrno() == EINVAL)
890#else
891 if (TSystem::GetErrno() == EIDRM)
892#endif
893 fSemaphore = -1;
894#if !defined(R__FBSD)
895 if (TSystem::GetErrno() == EINTR) {
896 if (intr > 2)
897 return -1;
899 intr++;
900 goto again;
901 }
902#endif
903 }
904 }
905#else
906 // Enter Critical section to "write" lock
908 WaitForSingleObject((HANDLE)fhSemaphore,INFINITE);
909#endif
910#endif
911
912 // file might have grown, update mapping on reader to new size
913 if (!fWritable && fMmallocDesc) {
914 if (mmalloc_update_mapping(fMmallocDesc) == -1)
915 Error("AcquireSemaphore", "cannot update mapping");
916 }
917
918 return 0;
919}
920
921////////////////////////////////////////////////////////////////////////////////
922/// Release semaphore. Returns 0 if OK, -1 on error.
923
925{
926#ifdef HAVE_SEMOP
927#ifndef WIN32
928 if (fSemaphore != -1) {
929 struct sembuf buf = { 0, 1, SEM_UNDO };
930 if (semop(fSemaphore, &buf, 1) == -1) {
931#if defined(R__FBSD) || defined(R__OBSD)
932 if (TSystem::GetErrno() == EINVAL)
933#else
934 if (TSystem::GetErrno() == EIDRM)
935#endif
936 fSemaphore = -1;
937 }
938 }
939#else
941 ReleaseMutex((HANDLE)fhSemaphore);
942#endif
943#endif
944 return 0;
945}
946
947////////////////////////////////////////////////////////////////////////////////
948/// Close a mapped file.
949///
950/// First detach mapped memory then close file.
951/// No member functions of a TMapFile that was opened in write mode
952/// may be called after Close() (this includes, of course, "delete" which
953/// would call the dtors). The option="dtor" is only used when called
954/// via the ~TMapFile.
955
957{
958 if (!fMmallocDesc) return;
959
960 TMapFile *shadow = FindShadowMapFile();
961 if (!shadow) {
962 Error("Close", "shadow map == 0, should never happen!");
963 return;
964 }
965
966 {
968 gROOT->GetListOfMappedFiles()->Remove(shadow);
969 gROOT->GetListOfMappedFiles()->Remove(this);
970 }
971
972 if (shadow->fWritable) {
975 }
976
977 if (fMmallocDesc) {
978 if (strcmp(option, "dtor"))
979 mmalloc_detach(fMmallocDesc);
980
981 // If writable cannot access fMmallocDesc anymore since
982 // it points to the just unmapped memory region. Any further
983 // access to this TMapFile will cause a crash.
984 if (!shadow->fWritable)
985 fMmallocDesc = 0;
986 }
987
988 if (shadow->fFd != -1)
989#ifndef WIN32
990 close(shadow->fFd);
991#else
992 CloseHandle((HANDLE)shadow->fFd);
993#endif
994
995 delete shadow;
996}
997
998////////////////////////////////////////////////////////////////////////////////
999/// Returns shadow map file.
1000
1002{
1004 TObjLink *lnk = ((TList *)gROOT->GetListOfMappedFiles())->LastLink();
1005 while (lnk) {
1006 TMapFile *mf = (TMapFile*)lnk->GetObject();
1007 if (mf->fVersion == -1 && fBaseAddr == mf->fBaseAddr && fSize == mf->fSize)
1008 return mf;
1009 lnk = lnk->Prev();
1010 }
1011 return 0;
1012}
1013
1014////////////////////////////////////////////////////////////////////////////////
1015/// Print some info about the mapped file.
1016
1018{
1019 Printf("Memory mapped file: %s", fName);
1020 Printf("Title: %s", fTitle);
1021 if (fMmallocDesc) {
1022 Printf("Option: %s", fOption);
1023 ULong_t size = (ULong_t)((struct mdesc *)fMmallocDesc)->top - fBaseAddr;
1024 Printf("Mapped Memory region: 0x%lx - 0x%lx (%.2f MB)", fBaseAddr, fBaseAddr + size,
1025 (float)size/1048576);
1026 Printf("Current breakval: 0x%lx", (ULong_t)GetBreakval());
1027 } else
1028 Printf("Option: file closed");
1029}
1030
1031////////////////////////////////////////////////////////////////////////////////
1032/// Returns kTRUE in case object is a folder (i.e. contains browsable lists).
1033
1035{
1036 if (fMmallocDesc && fVersion > 0) return kTRUE;
1037 return kFALSE;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041/// Browse contents of TMapFile.
1042
1044{
1045 if (b && fMmallocDesc) {
1046
1048
1049 TMapRec *mr = GetFirst();
1050 TKeyMapFile *keymap;
1051 if (!fBrowseList) fBrowseList = new TList();
1052 while (OrgAddress(mr)) {
1054 if (!keymap) {
1055 keymap = new TKeyMapFile(mr->GetName(fOffset),mr->GetClassName(fOffset),this);
1056 fBrowseList->Add(keymap);
1057 }
1058 b->Add(keymap, keymap->GetName());
1059 mr = mr->GetNext(fOffset);
1060 }
1061
1063
1064 }
1065}
1066
1067////////////////////////////////////////////////////////////////////////////////
1068/// Cd to associated directory.
1069
1070Bool_t TMapFile::cd(const char *path)
1071{
1072 if (fDirectory)
1073 return fDirectory->cd(path);
1074 return kFALSE;
1075}
1076
1077////////////////////////////////////////////////////////////////////////////////
1078/// List contents of TMapFile.
1079
1081{
1082 if (fMmallocDesc) {
1083
1084 ((TMapFile*)this)->AcquireSemaphore();
1085
1086 Printf("%-20s %-20s %-10s", "Object", "Class", "Size");
1087 if (!fFirst)
1088 Printf("*** no objects stored in memory mapped file ***");
1089
1090 TMapRec *mr = GetFirst();
1091 while (OrgAddress(mr)) {
1092 Printf("%-20s %-20s %-10d", mr->GetName(fOffset),
1093 mr->GetClassName(fOffset), mr->fBufSize);
1094 mr = mr->GetNext(fOffset);
1095 }
1096
1097 ((TMapFile*)this)->ReleaseSemaphore();
1098
1099 }
1100}
1101
1102////////////////////////////////////////////////////////////////////////////////
1103/// Increment statistics for buffer sizes of objects in this file.
1104
1106{
1107 fWritten++;
1108 fSumBuffer += bufsize;
1109 fSum2Buffer += bufsize*bufsize;
1110}
1111
1112////////////////////////////////////////////////////////////////////////////////
1113/// Return the best buffer size for objects in this file.
1114///
1115/// The best buffer size is estimated based on the current mean value
1116/// and standard deviation of all objects written so far to this file.
1117/// Returns mean value + one standard deviation.
1118
1120{
1121 if (!fWritten) return TBuffer::kMinimalSize;
1123 Double_t rms2 = TMath::Abs(fSum2Buffer/fSumBuffer - mean*mean);
1124 return (Int_t)(mean + std::sqrt(rms2));
1125}
1126
1127////////////////////////////////////////////////////////////////////////////////
1128/// Return the current location in the memory region for this malloc heap which
1129/// represents the end of memory in use. Returns 0 if map file was closed.
1130
1132{
1133 if (!fMmallocDesc) return 0;
1134 return (void *)((struct mdesc *)fMmallocDesc)->breakval;
1135}
1136
1137////////////////////////////////////////////////////////////////////////////////
1138/// Create a memory mapped file.
1139///
1140/// This opens a file (to which the
1141/// memory will be mapped) and attaches a memory region to it.
1142/// Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE"
1143/// or "READ" (see TFile). The default open mode is "READ". The size
1144/// argument specifies the maximum size of shared memory file in bytes.
1145/// TMapFile's can only be created via this method. Create() enforces that
1146/// a TMapFile is always on the memory mapped heap (when "NEW", "CREATE"
1147/// or "RECREATE" are used).
1148
1149TMapFile *TMapFile::Create(const char *name, Option_t *option, Int_t size,
1150 const char *title)
1151{
1152 TMapFile *newMapFile;
1153 new TMapFile(name, title, option, size, newMapFile);
1154
1155 return newMapFile;
1156}
1157
1158////////////////////////////////////////////////////////////////////////////////
1159/// Set preferred map address.
1160///
1161/// Find out preferred map address as follows:
1162/// -# Run consumer program to find the preferred map address. Remember begin of mapped region, i.e. 0x40b4c000
1163/// ~~~{.cpp}
1164/// $ root
1165/// root [0] m = TMapFile::Create("dummy.map", "recreate", 10000000);
1166/// root [1] m.Print()
1167/// Memory mapped file: dummy.map
1168/// Title:
1169/// Option: CREATE
1170/// Mapped Memory region: 0x40b4c000 - 0x40d95f00 (2.29 MB)
1171/// Current breakval: 0x40b53000
1172/// root [2] .q
1173/// $ rm dummy.map
1174/// ~~~
1175/// -# Add to producer program, just before creating the TMapFile:
1176/// TMapFile::SetMapAddress(0x40b4c000);
1177///
1178/// Repeat this if more than one map file is being used.
1179/// The above procedure allow programs using, e.g., different number of
1180/// shared libraries (that cause the default mapping address to be
1181/// different) to create shared memory regions in the same location
1182/// without overwriting a shared library. The above assumes the consumer
1183/// program is larger (i.e. has more shared memory occupied) than the
1184/// producer. If this is not true inverse the procedure.
1185
1187{
1188 fgMapAddress = addr;
1189}
1190
1191////////////////////////////////////////////////////////////////////////////////
1192/// Return the base address at which we would like the next TMapFile's
1193/// mapped data to start.
1194///
1195/// For now, we let the system decide (start address 0). There are
1196/// a lot of issues to deal with here to make this work reasonably,
1197/// including:
1198/// - Avoid memory collisions with existing mapped address spaces
1199/// - Reclaim address spaces when their mmalloc heaps are unmapped
1200/// - When mmalloc heaps are shared between processes they have to be
1201/// mapped at the same addresses in each
1202///
1203/// Once created, a mmalloc heap that is to be mapped back in must be
1204/// mapped at the original address. I.e. each TMapFile will expect
1205/// to be remapped at it's original address. This becomes a problem if
1206/// the desired address is already in use.
1207
1209{
1210#ifdef R__HAVE_MMAP
1212 return (void *)fgMapAddress;
1213 else
1214 return (void *)-1;
1215#else
1216 return (void *)-1;
1217#endif
1218}
1219
1220////////////////////////////////////////////////////////////////////////////////
1221/// Need special "operator delete" in which we close the shared memory.
1222/// This has to be done after the dtor chain has been finished.
1223
1224void TMapFile::operator delete(void *ptr)
1225{
1226 mmalloc_detach(fgMmallocDesc);
1227 fgMmallocDesc = 0;
1228
1229 TObject::operator delete(ptr);
1230}
1231
1232////////////////////////////////////////////////////////////////////////////////
1233
1235{
1236 // Don't use gROOT so that this routine does not trigger TROOT's initialization
1237 // This is essential since this routine is called via operator delete
1238 // which is used during RegisterModule (i.e. during library loading, including the initial
1239 // start up). Using gROOT leads to recursive call to RegisterModule and initialization of
1240 // the interpreter in the middle of the execution of RegisterModule (i.e. undefined behavior).
1241 if (!ROOT::Internal::gROOTLocal || !ROOT::Internal::gROOTLocal->GetListOfMappedFiles())
1242 return 0;
1243
1244 TObjLink *lnk = ((TList *)ROOT::Internal::gROOTLocal->GetListOfMappedFiles())->LastLink();
1245 while (lnk) {
1246 TMapFile *mf = (TMapFile*)lnk->GetObject();
1247 if (!mf) return 0;
1248 if ((ULong_t)addr >= mf->fBaseAddr + mf->fOffset &&
1249 (ULong_t)addr < (ULong_t)mf->GetBreakval() + mf->fOffset)
1250 return mf;
1251 lnk = lnk->Prev();
1252 }
1253 return 0;
1254}
1255
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
int Int_t
Definition: RtypesCore.h:43
const Bool_t kFALSE
Definition: RtypesCore.h:90
unsigned long ULong_t
Definition: RtypesCore.h:53
long Long_t
Definition: RtypesCore.h:52
double Double_t
Definition: RtypesCore.h:57
const Bool_t kTRUE
Definition: RtypesCore.h:89
const char Option_t
Definition: RtypesCore.h:64
#define ClassImp(name)
Definition: Rtypes.h:361
#define gDirectory
Definition: TDirectory.h:229
char name[80]
Definition: TGX11.cxx:109
struct SetFreeIfTMapFile_t gSetFreeIfTMapFile
#define INVALID_HANDLE_VALUE
Definition: TMapFile.cxx:84
double sqrt(double)
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:59
#define gROOT
Definition: TROOT.h:406
void Printf(const char *fmt,...)
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2490
@ kFileExists
Definition: TSystem.h:43
@ kReadPermission
Definition: TSystem.h:46
@ kWritePermission
Definition: TSystem.h:45
R__EXTERN TSystem * gSystem
Definition: TSystem.h:556
#define R__LOCKGUARD(mutex)
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition: TBufferFile.h:46
@ kWrite
Definition: TBuffer.h:72
@ kRead
Definition: TBuffer.h:72
@ kMinimalSize
Definition: TBuffer.h:77
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4941
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2948
A ROOT file is structured in Directories (like a file system).
virtual void Build(TFile *motherFile=nullptr, TDirectory *motherDir=nullptr)
Definition: TDirectory.h:132
void SetName(const char *newname) override
Set the name for directory If the directory name is changed after the directory was written once,...
virtual void SetMother(TObject *mother)
Definition: TDirectory.h:200
virtual Bool_t cd(const char *path=nullptr)
Change current directory to "this" directory.
Definition: TDirectory.cxx:498
Utility class for browsing TMapFile objects.
Definition: TKeyMapFile.h:20
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:577
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:469
This class implements a shared memory region mapped to a file.
Definition: TMapFile.h:25
static TMapFile * WhichMapFile(void *addr)
Definition: TMapFile.cxx:1234
static Long_t fgMapAddress
Map to this address, set address via SetMapAddress()
Definition: TMapFile.h:51
void * GetBreakval() const
Return the current location in the memory region for this malloc heap which represents the end of mem...
Definition: TMapFile.cxx:1131
Int_t fWritten
Number of objects written sofar.
Definition: TMapFile.h:47
static TMapFile * Create(const char *name, Option_t *option="READ", Int_t size=kDefaultMapSize, const char *title="")
Create a memory mapped file.
Definition: TMapFile.cxx:1149
TMapRec * fLast
Last object in list of shared objects.
Definition: TMapFile.h:39
Int_t fVersion
ROOT version (or -1 for shadow map file)
Definition: TMapFile.h:31
Int_t fSemaphore
Modification semaphore (or getpid() for WIN32)
Definition: TMapFile.h:44
Long_t fOffset
Offset in bytes for region mapped by reader.
Definition: TMapFile.h:40
void Close(Option_t *option="")
Close a mapped file.
Definition: TMapFile.cxx:956
TDirectory * fDirectory
Pointer to directory associated to this mapfile.
Definition: TMapFile.h:41
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
Definition: TMapFile.cxx:1105
void Update(TObject *obj=0)
Update an object (or all objects, if obj == 0) in shared memory.
Definition: TMapFile.cxx:636
TObject * Get(const char *name, TObject *retObj=nullptr)
Return pointer to object retrieved from shared memory.
Definition: TMapFile.cxx:777
ULong_t fhSemaphore
HANDLE of WIN32 Mutex object to implement semaphore.
Definition: TMapFile.h:45
char * fTitle
Title of mapped file.
Definition: TMapFile.h:33
void InitDirectory()
Create the directory associated to this mapfile.
Definition: TMapFile.cxx:582
void RemoveAll()
Remove all objects from shared memory.
Definition: TMapFile.cxx:752
Double_t fSum2Buffer
Sum of squares of buffer sizes of objects written so far.
Definition: TMapFile.h:49
Bool_t fWritable
TRUE if mapped file opened in RDWR mode.
Definition: TMapFile.h:43
void * OrgAddress(void *addr) const
Definition: TMapFile.h:97
Bool_t IsFolder() const
Returns kTRUE in case object is a folder (i.e. contains browsable lists).
Definition: TMapFile.cxx:1034
void DeleteSemaphore()
Delete the semaphore.
Definition: TMapFile.cxx:854
TList * fBrowseList
List of KeyMapFile objects.
Definition: TMapFile.h:42
TMapRec * fFirst
List of streamed objects is shared memory.
Definition: TMapFile.h:38
Int_t fFd
Descriptor of mapped file.
Definition: TMapFile.h:30
static void * MapToAddress()
Return the base address at which we would like the next TMapFile's mapped data to start.
Definition: TMapFile.cxx:1208
TObject * fGetting
Don't deadlock in update mode, when from Get() Add() is called.
Definition: TMapFile.h:46
TMapFile * FindShadowMapFile()
Returns shadow map file.
Definition: TMapFile.cxx:1001
void Browse(TBrowser *b)
Browse contents of TMapFile.
Definition: TMapFile.cxx:1043
void ls(Option_t *option="") const
List contents of TMapFile.
Definition: TMapFile.cxx:1080
void * fMmallocDesc
Pointer to mmalloc descriptor.
Definition: TMapFile.h:35
Double_t fSumBuffer
Sum of buffer sizes of objects written sofar.
Definition: TMapFile.h:48
static void * fgMmallocDesc
Used in Close() and operator delete()
Definition: TMapFile.h:52
void CreateSemaphore(Int_t pid=0)
Create semaphore used for synchronizing access to shared memory.
Definition: TMapFile.cxx:824
Int_t fSize
Original start size of memory mapped region.
Definition: TMapFile.h:37
TObject * Remove(TObject *obj, Bool_t lock)
Remove object from shared memory.
Definition: TMapFile.cxx:676
Int_t ReleaseSemaphore()
Release semaphore. Returns 0 if OK, -1 on error.
Definition: TMapFile.cxx:924
static void SetMapAddress(Long_t addr)
Set preferred map address.
Definition: TMapFile.cxx:1186
ULong_t fBaseAddr
Base address of mapped memory region.
Definition: TMapFile.h:36
char * fName
Name of mapped file.
Definition: TMapFile.h:32
Bool_t cd(const char *path=0)
Cd to associated directory.
Definition: TMapFile.cxx:1070
TMapFile()
Default ctor. Does not much except setting some basic values.
Definition: TMapFile.cxx:200
char * fOption
Directory creation options.
Definition: TMapFile.h:34
friend class TMapRec
Definition: TMapFile.h:27
Int_t AcquireSemaphore()
Acquire semaphore. Returns 0 if OK, -1 on error.
Definition: TMapFile.cxx:879
const char * GetName() const
Returns name of object.
Definition: TMapFile.h:89
void Add(const TObject *obj, const char *name="")
Add an object to the list of objects to be stored in shared memory.
Definition: TMapFile.cxx:597
virtual ~TMapFile()
TMapFiles may not be deleted, since we want to keep the complete TMapFile object in the mapped file f...
Definition: TMapFile.cxx:549
const char * GetTitle() const
Returns title of object.
Definition: TMapFile.h:92
void Print(Option_t *option="") const
Print some info about the mapped file.
Definition: TMapFile.cxx:1017
Int_t GetBestBuffer()
Return the best buffer size for objects in this file.
Definition: TMapFile.cxx:1119
TMapRec * GetFirst() const
Definition: TMapFile.h:93
Keep track of an object in the mapped file.
Definition: TMapFile.h:128
TObject * fObject
Pointer to original object.
Definition: TMapFile.h:135
const char * GetClassName(Long_t offset=0) const
Definition: TMapFile.h:147
Int_t fBufSize
Buffer size.
Definition: TMapFile.h:137
TMapRec(const TMapRec &)=delete
char * fName
Object name.
Definition: TMapFile.h:133
TMapRec * fNext
Next MapRec in list.
Definition: TMapFile.h:138
TMapRec * GetNext(Long_t offset=0) const
Definition: TMapFile.h:151
TObject * GetObject() const
This method returns a pointer to the original object.
Definition: TMapFile.cxx:187
void * GetBuffer(Long_t offset=0) const
Definition: TMapFile.h:148
char * fClassName
Class name.
Definition: TMapFile.h:134
const char * GetName(Long_t offset=0) const
Definition: TMapFile.h:146
void * fBuffer
Buffer containing object of class name.
Definition: TMapFile.h:136
~TMapRec()
Destructor.
Definition: TMapFile.cxx:175
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition: TNamed.cxx:164
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition: TObject.cxx:905
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:128
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:877
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:891
static void SetDtorOnly(void *obj)
Set destructor only flag.
Definition: TObject.cxx:988
void MakeZombie()
Definition: TObject.h:49
static Bool_t HasCustomNewDelete()
return the has custom delete flag
Definition: TStorage.cxx:490
Basic string class.
Definition: TString.h:131
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition: TString.cxx:418
@ kIgnoreCase
Definition: TString.h:263
static void ResetErrno()
Static function resetting system error number.
Definition: TSystem.cxx:274
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition: TSystem.cxx:1269
static Int_t GetErrno()
Static function returning system error number.
Definition: TSystem.cxx:258
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition: TSystem.cxx:1291
virtual int Unlink(const char *name)
Unlink, i.e.
Definition: TSystem.cxx:1376
const Int_t n
Definition: legend1.C:16
#define FALSE
Definition: mesh.c:45
R__EXTERN TROOT * gROOTLocal
Definition: TROOT.h:379
R__EXTERN FreeIfTMapFile_t * gFreeIfTMapFile
Definition: TStorage.h:148
R__EXTERN void * gMmallocDesc
Definition: TStorage.h:149
Short_t Abs(Short_t d)
Definition: TMathBase.h:120