Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 <cerrno>
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__WINGCC)
106#define HAVE_SEMOP
107#include <sys/types.h>
108#include <sys/ipc.h>
109#include <sys/sem.h>
110#if !defined(WIN32) && !defined(R__MACOSX)
111union semun {
112 int val; // value for SETVAL
113 struct semid_ds *buf; // buffer for IPC_STAT & IPC_SET
114 ushort *array; // array for GETALL & SETALL
115};
116#endif
117#if defined(R__LINUX) || defined(R__LYNXOS) || defined(R__HURD)
118# define SEM_A 0200 // alter permission
119# define SEM_R 0400 // read permission
120#endif
121#endif
122
123
126
127//void *ROOT::Internal::gMmallocDesc = 0; //is initialized in TStorage.cxx
128
129
130namespace {
131////////////////////////////////////////////////////////////////////////////////
132/// Delete memory and return true if memory belongs to a TMapFile.
133 static bool FreeIfTMapFile(void* ptr) {
134 if (TMapFile *mf = TMapFile::WhichMapFile(ptr)) {
135 if (mf->IsWritable())
136 ::mfree(mf->GetMmallocDesc(), ptr);
137 return true;
138 }
139 return false;
140 }
141
142/// Return the memory mapped start location corresponding to the user pointer
143/// if any. Return `nullptr` otherwise.
144 static void *GetMapFileMallocDesc(void *userptr)
145 {
147 {
148 return mf->GetMmallocDesc();
149 }
150 return nullptr;
151 }
152}
153
154
155////////////////////////////////////////////////////////////////////////////////
156/// Set ROOT::Internal::gFreeIfTMapFile on library load.
157
168
169
170////////////////////////////////////////////////////////////////////////////////
171//// Constructor.
172
173TMapRec::TMapRec(const char *name, const TObject *obj, Int_t size, void *buf)
174{
175 fName = StrDup(name);
176 fClassName = 0;
177 fObject = (TObject*)obj;
178 fBuffer = buf;
179 fBufSize = size;
180 fNext = 0;
181}
182
183////////////////////////////////////////////////////////////////////////////////
184/// Destructor.
185
187{
188 delete [] fName;
189 delete [] fClassName;
190}
191
192////////////////////////////////////////////////////////////////////////////////
193/// This method returns a pointer to the original object.
194
195/// NOTE: this pointer is only valid in the process that produces the shared
196/// memory file. In a consumer process this pointer is illegal! Be careful.
197
199{
200 return fObject;
201}
202
203
204
205
206
207////////////////////////////////////////////////////////////////////////////////
208/// Default ctor. Does not much except setting some basic values.
209
211{
212 fFd = -1;
213 fVersion = 0;
214 fName = nullptr;
215 fTitle = nullptr;
216 fOption = nullptr;
217 fMmallocDesc = nullptr;
218 fBaseAddr = 0;
219 fSize = 0;
220 fFirst = nullptr;
221 fLast = nullptr;
222 fOffset = 0;
223 fDirectory = nullptr;
224 fBrowseList = nullptr;
226 fSemaphore = -1;
227 fhSemaphore = 0;
228 fGetting = nullptr;
229 fWritten = 0;
230 fSumBuffer = 0;
231 fSum2Buffer = 0;
232}
233
234////////////////////////////////////////////////////////////////////////////////
235/// Create a memory mapped file.
236///
237/// This opens a file (to which the
238/// memory will be mapped) and attaches a memory region to it.
239/// Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE" or
240/// "READ" (see TFile). The default open mode is "READ". The size
241/// argument specifies the maximum size of shared memory file in bytes.
242/// This protected ctor is called via the static Create() method.
243
244TMapFile::TMapFile(const char *name, const char *title, Option_t *option,
246{
247#ifndef WIN32
248 fFd = -1;
249 fSemaphore = -1;
250 fhSemaphore = 0;
251#else
254#endif
255 fMmallocDesc = nullptr;
256 fSize = size;
257 fFirst = 0;
258 fOffset = 0;
259 fVersion = gROOT->GetVersionInt();
260 fTitle = StrDup(title);
262 fDirectory = nullptr;
263 fBrowseList = nullptr;
264 fGetting = nullptr;
265 fWritten = 0;
266 fSumBuffer = 0;
267 fSum2Buffer = 0;
268
269 char *cleanup = nullptr;
270 Bool_t create = kFALSE;
271 Bool_t recreate, update, read;
272
273 {
274 TString opt = option;
275
276 if (!opt.CompareTo("NEW", TString::kIgnoreCase) ||
277 !opt.CompareTo("CREATE", TString::kIgnoreCase))
278 create = kTRUE;
279 recreate = opt.CompareTo("RECREATE", TString::kIgnoreCase)
280 ? kFALSE : kTRUE;
281 update = opt.CompareTo("UPDATE", TString::kIgnoreCase)
282 ? kFALSE : kTRUE;
283 read = opt.CompareTo("READ", TString::kIgnoreCase)
284 ? kFALSE : kTRUE;
285 if (!create && !recreate && !update && !read) {
286 read = kTRUE;
287 delete [] fOption;
288 fOption = StrDup("READ");
289 }
290 }
291
292 const char *fname;
293 if ((fName = gSystem->ExpandPathName(name))) {
294 fname = fName;
295 } else {
296 Error("TMapFile", "error expanding path %s", name);
297 goto zombie;
298 }
299
300 if (recreate) {
304 create = kTRUE;
305 delete [] fOption;
306 fOption = StrDup("CREATE");
307 }
308 if (create && !gSystem->AccessPathName(fname, kFileExists)) {
309 Error("TMapFile", "file %s already exists", fname);
310 goto zombie;
311 }
312 if (update) {
314 update = kFALSE;
315 create = kTRUE;
316 }
318 Error("TMapFile", "no write permission, could not open file %s", fname);
319 goto zombie;
320 }
321 }
322 if (read) {
324 Error("TMapFile", "file %s does not exist", fname);
325 goto zombie;
326 }
328 Error("TMapFile", "no read permission, could not open file %s", fname);
329 goto zombie;
330 }
331 }
332
333 // Open file to which memory will be mapped
334 if (create || update) {
335#ifndef WIN32
336 fFd = open(fname, O_RDWR | O_CREAT, 0644);
337#else
338 fFd = (Longptr_t) CreateFile(fname, // pointer to name of the file
339 GENERIC_WRITE | GENERIC_READ, // access (read-write) mode
340 FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
341 NULL, // pointer to security attributes
342 OPEN_ALWAYS, // how to create
343 FILE_ATTRIBUTE_TEMPORARY, // file attributes
344 (HANDLE) NULL); // handle to file with attributes to copy
345#endif
347 SysError("TMapFile", "file %s can not be opened", fname);
348 goto zombie;
349 }
351 } else {
352#ifndef WIN32
353 fFd = open(fname, O_RDONLY);
354#else
355 fFd = (Longptr_t) CreateFile(fname, // pointer to name of the file
356 GENERIC_READ, // access (read-write) mode
357 FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode
358 NULL, // pointer to security attributes
359 OPEN_EXISTING, // how to create
360 FILE_ATTRIBUTE_TEMPORARY, // file attributes
361 (HANDLE) NULL); // handle to file with attributes to copy
362#endif
364 SysError("TMapFile", "file %s can not be opened for reading", fname);
365 goto zombie;
366 }
368 }
369
370 // Attach memory region to file.
371 void *mapto;
373
374 if (((mapto = MapToAddress()) == (void *)-1) ||
376 ((fMmallocDesc = mmalloc_attach(fFd, mapto, fSize)) == 0)) {
377#else
378 ((fMmallocDesc = mmalloc_attach((HANDLE) fFd, mapto, fSize)) == 0)) {
379#endif
380
381 if (mapto == (void *)-1) {
382 Error("TMapFile", "no memory mapped file capability available\n"
383 "Use rootn.exe or link application against \"-lNew\"");
384 } else {
385 if (fMmallocDesc == 0 && fWritable)
386 Error("TMapFile", "mapped file not in mmalloc format or\n"
387 "already open in RW mode by another process");
388 if (fMmallocDesc == 0 && !fWritable)
389 Error("TMapFile", "mapped file not in mmalloc format");
390 }
391#ifndef WIN32
392 close(fFd);
393#else
394 CloseHandle((HANDLE) fFd);
395#endif
396 fFd = -1;
397 if (create)
399 goto zombie;
400
401 } else if ((mapfil = (TMapFile *) mmalloc_getkey(fMmallocDesc, 0)) != 0) {
402
403 // File contains mmalloc heap. If we are in write mode and mapped
404 // file already connected in write mode switch to read-only mode.
405 // Check if ROOT versions are compatible.
406 // If so update mapped version of TMapFile to reflect current
407 // situation (only if not opened in READ mode).
408 if (mapfil->fVersion != fVersion) {
409 Error("TMapFile", "map file %s (%d) incompatible with current ROOT version (%d)",
410 fname, mapfil->fVersion, fVersion);
412#ifndef WIN32
413 close(fFd);
414#else
415 CloseHandle((HANDLE) fFd);
416#endif
417 fFd = -1;
418 fMmallocDesc = 0;
419 goto zombie;
420 }
421
422 if (mapfil->fWritable && fWritable) {
423 Warning("TMapFile", "map file already open in write mode, opening in read-only mode");
425 }
426
427 fBaseAddr = mapfil->fBaseAddr;
428 fSize = mapfil->fSize;
429
430 if (fWritable) {
431 // create new TMapFile object in mapped heap to get correct vtbl ptr
434 TMapFile *mf = new TMapFile(*mapfil);
435 mf->fFd = fFd;
436 mf->fWritable = kTRUE;
437 cleanup = mf->fOption;
438 mf->fOption = StrDup(fOption);
439 mf->fSemaphore = fSemaphore;
440#ifdef WIN32
441 mf->CreateSemaphore(fSemaphore);
442#endif
445 mapfil = mf;
446 } else {
447 ROOT::Internal::gMmallocDesc = 0; // make sure we are in sbrk heap
448 fOffset = ((struct mdesc *) fMmallocDesc)->offset;
450 delete [] mf->fOption;
451 mf->fFd = fFd;
452 mf->fOption = StrDup("READ");
453 mf->fMmallocDesc = fMmallocDesc;
454 mf->fWritable = kFALSE;
455 mapfil = mf;
456 }
457
458 // store shadow mapfile (it contains the real fFd in case map
459 // is not writable)
460 fVersion = -1; // make this the shadow map file
462 gROOT->GetListOfMappedFiles()->AddLast(this);
463
464 } else {
465
466 // New file. If the file is writable create a new copy of the
467 // TMapFile which will now be allocated on the memory mapped heap.
468 if (!fWritable) {
469 Error("TMapFile", "map file is not writable");
471#ifndef WIN32
472 close(fFd);
473#else
474 CloseHandle((HANDLE) fFd);
475#endif
476 fFd = -1;
477 fMmallocDesc = 0;
478 goto zombie;
479 }
480
481 fBaseAddr = (ULongptr_t)((struct mdesc *) fMmallocDesc)->base;
482
484
486
487 mapfil = new TMapFile(*this);
489
491
492 // store shadow mapfile
493 fVersion = -1; // make this the shadow map file
495 gROOT->GetListOfMappedFiles()->AddLast(this);
496
497 }
498
499 mapfil->InitDirectory();
500 {
502 gROOT->GetListOfMappedFiles()->AddFirst(mapfil);
503 }
504
505 if (cleanup) delete [] cleanup;
506
508
509 return;
510
511zombie:
512 // error in file opening occured, make this object a zombie
513 MakeZombie();
514 newMapFile = this;
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Private copy ctor.
520///
521/// Used by the ctor to create a new version
522/// of TMapFile in the memory mapped heap. It's main purpose is to
523/// correctly create the string data members.
524
526{
527 fFd = f.fFd;
528 fVersion = f.fVersion;
529 fName = StrDup((char *)((Longptr_t)f.fName + offset));
530 fTitle = StrDup((char *)((Longptr_t)f.fTitle + offset));
531 fOption = StrDup((char *)((Longptr_t)f.fOption + offset));
532 fMmallocDesc = f.fMmallocDesc;
533 fBaseAddr = f.fBaseAddr;
534 fSize = f.fSize;
535 fFirst = f.fFirst;
536 fLast = f.fLast;
537 fWritable = f.fWritable;
538 fSemaphore = f.fSemaphore;
539 fOffset = offset;
540 fDirectory = nullptr;
541 fBrowseList = nullptr;
542 fGetting = nullptr;
543 fWritten = f.fWritten;
544 fSumBuffer = f.fSumBuffer;
545 fSum2Buffer = f.fSum2Buffer;
546#ifdef WIN32
548#else
549 fhSemaphore = f.fhSemaphore;
550#endif
551}
552
553////////////////////////////////////////////////////////////////////////////////
554/// TMapFiles may not be deleted, since we want to keep the complete
555/// TMapFile object in the mapped file for later re-use. To enforce this
556/// the delete operator has been made private. Use Close() to properly
557/// terminate a TMapFile (also done via the TROOT dtor).
558
560{
562 delete fDirectory; fDirectory = nullptr;
563 if (fBrowseList) {
565 delete fBrowseList;
566 fBrowseList = nullptr;
567 }
568
569
570 // if shadow map file we are done here
571 if (fVersion == -1)
572 return;
573
574 // Writable mapfile is allocated in mapped memory. This object should
575 // not be deleted by ::operator delete(), because it is needed if we
576 // want to connect later to the file again.
577 if (fWritable)
579
580 Close("dtor");
581
582 // Tell TMapFile::operator delete which memory address to detach
583 // The detaching must be done after the whole object has been tear down
584 // (including base classes).
586
587 delete [] fName; fName = nullptr;
588 delete [] fOption; fOption = nullptr;
589 delete [] fTitle; fTitle = nullptr;
590}
591
592////////////////////////////////////////////////////////////////////////////////
593/// Create the directory associated to this mapfile
594
605
606////////////////////////////////////////////////////////////////////////////////
607/// Add an object to the list of objects to be stored in shared memory.
608/// To place the object actually into shared memory call Update().
609
610void TMapFile::Add(const TObject *obj, const char *name)
611{
612 if (!fWritable || !fMmallocDesc) return;
613
614 Bool_t lock = fGetting != obj ? kTRUE : kFALSE;
615
616 if (lock)
618
619 const char *n;
620 if (name && *name)
621 n = name;
622 else
623 n = obj->GetName();
624
625 if (Remove(n, kFALSE)) {
626 //Warning("Add", "replaced object with same name %s", n);
627 }
628
630 TMapRec *mr = new TMapRec(n, obj, 0, 0);
632
633 if (!fFirst) {
634 fFirst = mr;
635 fLast = mr;
636 } else {
637 fLast->fNext = mr;
638 fLast = mr;
639 }
640
641
642 if (lock)
644}
645
646namespace {
647 // Wrapper around TStorage::ReAlloc to update the signature.
648 char *MemMapAllocFunc(char *oldptr, size_t newsize, size_t oldsize)
649 {
650 return reinterpret_cast<char*>(TStorage::ReAlloc(oldptr, newsize, oldsize));
651 }
652}
653
654////////////////////////////////////////////////////////////////////////////////
655/// Update an object (or all objects, if obj == 0) in shared memory.
656
658{
659 if (!fWritable || !fMmallocDesc) return;
660
662
663 Bool_t all = (obj == 0) ? kTRUE : kFALSE;
664
665 TMapRec *mr = fFirst;
666 while (mr) {
667 if (all || mr->fObject == obj) {
668 TBufferFile *b;
669 if (!mr->fBufSize) {
670 const char *cname = mr->fObject->ClassName();
671 mr->fBufSize = GetBestBuffer();
672
674 mr->fBuffer = new char[mr->fBufSize];
675 mr->fClassName = StrDup(cname);
677 }
678 b = new TBufferFile(TBuffer::kWrite, mr->fBufSize, mr->fBuffer, kFALSE, MemMapAllocFunc);
679 b->MapObject(mr->fObject); //register obj in map to handle self reference
680 mr->fObject->Streamer(*b);
681 mr->fBufSize = b->BufferSize() + 8; // extra space at end of buffer (used for free block count) there on
682 mr->fBuffer = b->Buffer();
683 SumBuffer(b->Length());
684 b->DetachBuffer();
685 delete b;
686 }
687 mr = mr->fNext;
688 }
689
691}
692
693////////////////////////////////////////////////////////////////////////////////
694/// Remove object from shared memory.
695///
696/// Returns pointer to removed object if successful, 0 otherwise.
697
699{
700 if (!fWritable || !fMmallocDesc) return 0;
701
702 if (lock)
704
705 TObject *retObj = 0;
706 TMapRec *prev = 0, *mr = fFirst;
707 while (mr) {
708 if (mr->fObject == obj) {
709 if (mr == fFirst) {
710 fFirst = mr->fNext;
711 if (mr == fLast)
712 fLast = 0;
713 } else {
714 prev->fNext = mr->fNext;
715 if (mr == fLast)
716 fLast = prev;
717 }
718 retObj = obj;
719 delete mr;
720 break;
721 }
722 prev = mr;
723 mr = mr->fNext;
724 }
725
726 if (lock)
728
729 return retObj;
730}
731
732////////////////////////////////////////////////////////////////////////////////
733/// Remove object by name from shared memory.
734///
735/// Returns pointer to removed object if successful, 0 otherwise.
736
738{
739 if (!fWritable || !fMmallocDesc) return 0;
740
741 if (lock)
743
744 TObject *retObj = 0;
745 TMapRec *prev = 0, *mr = fFirst;
746 while (mr) {
747 if (!strcmp(mr->fName, name)) {
748 if (mr == fFirst) {
749 fFirst = mr->fNext;
750 if (mr == fLast)
751 fLast = 0;
752 } else {
753 prev->fNext = mr->fNext;
754 if (mr == fLast)
755 fLast = prev;
756 }
757 retObj = mr->fObject;
758 delete mr;
759 break;
760 }
761 prev = mr;
762 mr = mr->fNext;
763 }
764
765 if (lock)
767
768 return retObj;
769}
770
771////////////////////////////////////////////////////////////////////////////////
772/// Remove all objects from shared memory.
773
775{
776 if (!fWritable || !fMmallocDesc) return;
777
779
780 TMapRec *mr = fFirst;
781 while (mr) {
782 TMapRec *t = mr;
783 mr = mr->fNext;
784 delete t;
785 }
786 fFirst = fLast = 0;
787
789}
790
791////////////////////////////////////////////////////////////////////////////////
792/// Return pointer to object retrieved from shared memory.
793///
794/// The object must
795/// be deleted after use. If delObj is a pointer to a previously allocated
796/// object it will be deleted. Returns 0 in case object with the given
797/// name does not exist.
798
800{
801 if (!fMmallocDesc) return 0;
802
804
805 delete delObj;
806
807 TObject *obj = 0;
808 TMapRec *mr = GetFirst();
809 while (OrgAddress(mr)) {
810 if (!strcmp(mr->GetName(fOffset), name)) {
811 if (!mr->fBufSize) goto release;
812 TClass *cl = TClass::GetClass(mr->GetClassName(fOffset));
813 if (!cl) {
814 Error("Get", "unknown class %s", mr->GetClassName(fOffset));
815 goto release;
816 }
817
818 obj = (TObject *)cl->New();
819 if (!obj) {
820 Error("Get", "cannot create new object of class %s", mr->GetClassName(fOffset));
821 goto release;
822 }
823
824 fGetting = obj;
825 TBufferFile *b = new TBufferFile(TBuffer::kRead, mr->fBufSize, mr->GetBuffer(fOffset));
826 b->MapObject(obj); //register obj in map to handle self reference
827 obj->Streamer(*b);
828 b->DetachBuffer();
829 delete b;
830 fGetting = 0;
831 goto release;
832 }
833 mr = mr->GetNext(fOffset);
834 }
835
836release:
838
839 return obj;
840}
841
842////////////////////////////////////////////////////////////////////////////////
843/// Create semaphore used for synchronizing access to shared memory.
844
845#ifndef WIN32
847#else
848void TMapFile::CreateSemaphore(int pid)
849#endif
850{
851#ifdef HAVE_SEMOP
852#ifndef WIN32
853 // create semaphore to synchronize access (should use read/write lock)
854 fSemaphore = semget(IPC_PRIVATE, 1, SEM_R|SEM_A|(SEM_R>>3)|(SEM_A>>3)|
855 (SEM_R>>6)|(SEM_A>>6));
856
857 // set semaphore to 1
858 if (fSemaphore != -1) {
859 union semun set;
860 set.val = 1;
861 semctl(fSemaphore, 0, SETVAL, set);
862 }
863#else
864 char buffer[] ="ROOT_Semaphore_xxxxxxxx";
865 int lbuf = strlen(buffer);
866 if (!pid) fSemaphore = getpid();
867 fhSemaphore = (ULongptr_t)CreateMutex(NULL,FALSE,itoa(fSemaphore,&buffer[lbuf-8],16));
868 if (fhSemaphore == 0) fSemaphore = (Longptr_t)INVALID_HANDLE_VALUE;
869#endif
870#endif
871}
872
873////////////////////////////////////////////////////////////////////////////////
874/// Delete the semaphore.
875
877{
878#ifdef HAVE_SEMOP
879 // remove semaphore
880#ifndef WIN32
881 if (fSemaphore != -1) {
882 int semid = fSemaphore;
883 fSemaphore = -1;
884 union semun set;
885 set.val = 0;
886 semctl(semid, 0, IPC_RMID, set);
887 }
888#else
890 CloseHandle((HANDLE)fhSemaphore);
891 fhSemaphore = 0;
893 }
894#endif
895#endif
896}
897
898////////////////////////////////////////////////////////////////////////////////
899/// Acquire semaphore. Returns 0 if OK, -1 on error.
900
902{
903#ifdef HAVE_SEMOP
904#ifndef WIN32
905 if (fSemaphore != -1) {
906 struct sembuf buf = { 0, -1, SEM_UNDO };
907 int intr = 0;
908again:
909 if (semop(fSemaphore, &buf, 1) == -1) {
910#if defined(R__FBSD) || defined(R__OBSD)
911 if (TSystem::GetErrno() == EINVAL)
912#else
913 if (TSystem::GetErrno() == EIDRM)
914#endif
915 fSemaphore = -1;
916#if !defined(R__FBSD)
917 if (TSystem::GetErrno() == EINTR) {
918 if (intr > 2)
919 return -1;
921 intr++;
922 goto again;
923 }
924#endif
925 }
926 }
927#else
928 // Enter Critical section to "write" lock
931#endif
932#endif
933
934 // file might have grown, update mapping on reader to new size
935 if (!fWritable && fMmallocDesc) {
937 Error("AcquireSemaphore", "cannot update mapping");
938 }
939
940 return 0;
941}
942
943////////////////////////////////////////////////////////////////////////////////
944/// Release semaphore. Returns 0 if OK, -1 on error.
945
947{
948#ifdef HAVE_SEMOP
949#ifndef WIN32
950 if (fSemaphore != -1) {
951 struct sembuf buf = { 0, 1, SEM_UNDO };
952 if (semop(fSemaphore, &buf, 1) == -1) {
953#if defined(R__FBSD) || defined(R__OBSD)
954 if (TSystem::GetErrno() == EINVAL)
955#else
956 if (TSystem::GetErrno() == EIDRM)
957#endif
958 fSemaphore = -1;
959 }
960 }
961#else
963 ReleaseMutex((HANDLE)fhSemaphore);
964#endif
965#endif
966 return 0;
967}
968
969////////////////////////////////////////////////////////////////////////////////
970/// Close a mapped file.
971///
972/// First detach mapped memory then close file.
973/// No member functions of a TMapFile that was opened in write mode
974/// may be called after Close() (this includes, of course, "delete" which
975/// would call the dtors). The option="dtor" is only used when called
976/// via the ~TMapFile.
977
979{
980 if (!fMmallocDesc) return;
981
983 if (!shadow) {
984 Error("Close", "shadow map == 0, should never happen!");
985 return;
986 }
987
988 {
990 gROOT->GetListOfMappedFiles()->Remove(shadow);
991 gROOT->GetListOfMappedFiles()->Remove(this);
992 }
993
994 if (shadow->fWritable) {
997 }
998
999 if (fMmallocDesc) {
1000 if (strcmp(option, "dtor"))
1002
1003 // If writable cannot access fMmallocDesc anymore since
1004 // it points to the just unmapped memory region. Any further
1005 // access to this TMapFile will cause a crash.
1006 if (!shadow->fWritable)
1007 fMmallocDesc = 0;
1008 }
1009
1010 if (shadow->fFd != -1)
1011#ifndef WIN32
1012 close(shadow->fFd);
1013#else
1014 CloseHandle((HANDLE)shadow->fFd);
1015#endif
1016
1017 delete shadow;
1018}
1019
1020////////////////////////////////////////////////////////////////////////////////
1021/// Returns shadow map file.
1022
1024{
1026 TObjLink *lnk = ((TList *)gROOT->GetListOfMappedFiles())->LastLink();
1027 while (lnk) {
1028 TMapFile *mf = (TMapFile*)lnk->GetObject();
1029 if (mf->fVersion == -1 && fBaseAddr == mf->fBaseAddr && fSize == mf->fSize)
1030 return mf;
1031 lnk = lnk->Prev();
1032 }
1033 return 0;
1034}
1035
1036////////////////////////////////////////////////////////////////////////////////
1037/// Print some info about the mapped file.
1038
1040{
1041 Printf("Memory mapped file: %s", fName);
1042 Printf("Title: %s", fTitle);
1043 if (fMmallocDesc) {
1044 Printf("Option: %s", fOption);
1045 size_t size = (size_t)((struct mdesc *)fMmallocDesc)->top - fBaseAddr;
1046 Printf("Mapped Memory region: 0x%zx - 0x%zx (%.2f MB)", (size_t)fBaseAddr, (size_t)fBaseAddr + size,
1047 (float)size/1048576);
1048 Printf("Current breakval: 0x%zx", (size_t)GetBreakval());
1049 } else
1050 Printf("Option: file closed");
1051}
1052
1053////////////////////////////////////////////////////////////////////////////////
1054/// Returns kTRUE in case object is a folder (i.e. contains browsable lists).
1055
1057{
1058 if (fMmallocDesc && fVersion > 0) return kTRUE;
1059 return kFALSE;
1060}
1061
1062////////////////////////////////////////////////////////////////////////////////
1063/// Browse contents of TMapFile.
1064
1066{
1067 if (b && fMmallocDesc) {
1068
1070
1071 TMapRec *mr = GetFirst();
1073 if (!fBrowseList) fBrowseList = new TList();
1074 while (OrgAddress(mr)) {
1076 if (!keymap) {
1077 keymap = new TKeyMapFile(mr->GetName(fOffset),mr->GetClassName(fOffset),this);
1079 }
1080 b->Add(keymap, keymap->GetName());
1081 mr = mr->GetNext(fOffset);
1082 }
1083
1085
1086 }
1087}
1088
1089////////////////////////////////////////////////////////////////////////////////
1090/// Cd to associated directory.
1091
1092Bool_t TMapFile::cd(const char *path)
1093{
1094 if (fDirectory)
1095 return fDirectory->cd(path);
1096 return kFALSE;
1097}
1098
1099////////////////////////////////////////////////////////////////////////////////
1100/// List contents of TMapFile.
1101
1103{
1104 if (fMmallocDesc) {
1105
1106 ((TMapFile*)this)->AcquireSemaphore();
1107
1108 Printf("%-20s %-20s %-10s", "Object", "Class", "Size");
1109 if (!fFirst)
1110 Printf("*** no objects stored in memory mapped file ***");
1111
1112 TMapRec *mr = GetFirst();
1113 while (OrgAddress(mr)) {
1114 Printf("%-20s %-20s %-10d", mr->GetName(fOffset),
1115 mr->GetClassName(fOffset), mr->fBufSize);
1116 mr = mr->GetNext(fOffset);
1117 }
1118
1119 ((TMapFile*)this)->ReleaseSemaphore();
1120
1121 }
1122}
1123
1124////////////////////////////////////////////////////////////////////////////////
1125/// Increment statistics for buffer sizes of objects in this file.
1126
1133
1134////////////////////////////////////////////////////////////////////////////////
1135/// Return the best buffer size for objects in this file.
1136///
1137/// The best buffer size is estimated based on the current mean value
1138/// and standard deviation of all objects written so far to this file.
1139/// Returns mean value + one standard deviation.
1140
1142{
1143 if (!fWritten) return TBuffer::kMinimalSize;
1145 Double_t rms2 = std::abs(fSum2Buffer/fSumBuffer - mean*mean);
1146 return (Int_t)(mean + std::sqrt(rms2));
1147}
1148
1149////////////////////////////////////////////////////////////////////////////////
1150/// Return the current location in the memory region for this malloc heap which
1151/// represents the end of memory in use. Returns 0 if map file was closed.
1152
1154{
1155 if (!fMmallocDesc) return 0;
1156 return (void *)((struct mdesc *)fMmallocDesc)->breakval;
1157}
1158
1159////////////////////////////////////////////////////////////////////////////////
1160/// Create a memory mapped file.
1161///
1162/// This opens a file (to which the
1163/// memory will be mapped) and attaches a memory region to it.
1164/// Option can be either: "NEW", "CREATE", "RECREATE", "UPDATE"
1165/// or "READ" (see TFile). The default open mode is "READ". The size
1166/// argument specifies the maximum size of shared memory file in bytes.
1167/// TMapFile's can only be created via this method. Create() enforces that
1168/// a TMapFile is always on the memory mapped heap (when "NEW", "CREATE"
1169/// or "RECREATE" are used).
1170
1172 const char *title)
1173{
1175 new TMapFile(name, title, option, size, newMapFile);
1176
1177 return newMapFile;
1178}
1179
1180////////////////////////////////////////////////////////////////////////////////
1181/// Set preferred map address.
1182///
1183/// Find out preferred map address as follows:
1184/// -# Run consumer program to find the preferred map address. Remember begin of mapped region, i.e. 0x40b4c000
1185/// ~~~{.cpp}
1186/// $ root
1187/// root [0] m = TMapFile::Create("dummy.map", "recreate", 10000000);
1188/// root [1] m.Print()
1189/// Memory mapped file: dummy.map
1190/// Title:
1191/// Option: CREATE
1192/// Mapped Memory region: 0x40b4c000 - 0x40d95f00 (2.29 MB)
1193/// Current breakval: 0x40b53000
1194/// root [2] .q
1195/// $ rm dummy.map
1196/// ~~~
1197/// -# Add to producer program, just before creating the TMapFile:
1198/// TMapFile::SetMapAddress(0x40b4c000);
1199///
1200/// Repeat this if more than one map file is being used.
1201/// The above procedure allow programs using, e.g., different number of
1202/// shared libraries (that cause the default mapping address to be
1203/// different) to create shared memory regions in the same location
1204/// without overwriting a shared library. The above assumes the consumer
1205/// program is larger (i.e. has more shared memory occupied) than the
1206/// producer. If this is not true inverse the procedure.
1207
1212
1213////////////////////////////////////////////////////////////////////////////////
1214/// Return the base address at which we would like the next TMapFile's
1215/// mapped data to start.
1216///
1217/// For now, we let the system decide (start address 0). There are
1218/// a lot of issues to deal with here to make this work reasonably,
1219/// including:
1220/// - Avoid memory collisions with existing mapped address spaces
1221/// - Reclaim address spaces when their mmalloc heaps are unmapped
1222/// - When mmalloc heaps are shared between processes they have to be
1223/// mapped at the same addresses in each
1224///
1225/// Once created, a mmalloc heap that is to be mapped back in must be
1226/// mapped at the original address. I.e. each TMapFile will expect
1227/// to be remapped at it's original address. This becomes a problem if
1228/// the desired address is already in use.
1229
1231{
1232#ifdef R__HAVE_MMAP
1234 return (void *)fgMapAddress;
1235 else
1236 return (void *)-1;
1237#else
1238 return (void *)-1;
1239#endif
1240}
1241
1242////////////////////////////////////////////////////////////////////////////////
1243/// Need special "operator delete" in which we close the shared memory.
1244/// This has to be done after the dtor chain has been finished.
1245
1246void TMapFile::operator delete(void *ptr)
1247{
1248 mmalloc_detach(fgMmallocDesc);
1249 fgMmallocDesc = 0;
1250
1251 TObject::operator delete(ptr);
1252}
1253
1254////////////////////////////////////////////////////////////////////////////////
1255
1257{
1258 // Don't use gROOT so that this routine does not trigger TROOT's initialization
1259 // This is essential since this routine is called via operator delete
1260 // which is used during RegisterModule (i.e. during library loading, including the initial
1261 // start up). Using gROOT leads to recursive call to RegisterModule and initialization of
1262 // the interpreter in the middle of the execution of RegisterModule (i.e. undefined behavior).
1263 if (!ROOT::Internal::gROOTLocal || !ROOT::Internal::gROOTLocal->GetListOfMappedFiles())
1264 return 0;
1265
1266 TObjLink *lnk = ((TList *)ROOT::Internal::gROOTLocal->GetListOfMappedFiles())->LastLink();
1267 while (lnk) {
1268 TMapFile *mf = (TMapFile*)lnk->GetObject();
1269 if (!mf) return 0;
1270 if ((ULongptr_t)addr >= mf->fBaseAddr + mf->fOffset &&
1271 (ULongptr_t)addr < (ULongptr_t)mf->GetBreakval() + mf->fOffset)
1272 return mf;
1273 lnk = lnk->Prev();
1274 }
1275 return 0;
1276}
1277
#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)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
long Longptr_t
Integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:89
unsigned long ULongptr_t
Unsigned integer large enough to hold a pointer (platform-dependent)
Definition RtypesCore.h:90
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char)
Definition RtypesCore.h:80
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define gDirectory
Definition TDirectory.h:385
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char cname
char name[80]
Definition TGX11.cxx:110
struct SetFreeIfTMapFile_t gSetFreeIfTMapFile
#define INVALID_HANDLE_VALUE
Definition TMapFile.cxx:84
R__EXTERN TVirtualMutex * gROOTMutex
Definition TROOT.h:63
#define gROOT
Definition TROOT.h:411
void Printf(const char *fmt,...)
Formats a string in a circular formatting buffer and prints the string.
Definition TString.cxx:2509
char * StrDup(const char *str)
Duplicate the string str.
Definition TString.cxx:2563
@ kFileExists
Definition TSystem.h:52
@ kReadPermission
Definition TSystem.h:55
@ kWritePermission
Definition TSystem.h:54
R__EXTERN TSystem * gSystem
Definition TSystem.h:572
#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:47
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
@ kMinimalSize
Definition TBuffer.h:78
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5017
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:2973
A ROOT file is structured in Directories (like a file system).
virtual void Build(TFile *motherFile=nullptr, TDirectory *motherDir=nullptr)
Definition TDirectory.h:187
virtual Bool_t cd()
Change current directory to "this" directory.
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:259
Utility class for browsing TMapFile objects.
Definition TKeyMapFile.h:20
A doubly linked list.
Definition TList.h:38
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:575
void Add(TObject *obj) override
Definition TList.h:81
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:467
This class implements a shared memory region mapped to a file.
Definition TMapFile.h:26
static TMapFile * WhichMapFile(void *addr)
void * GetBreakval() const
Return the current location in the memory region for this malloc heap which represents the end of mem...
Int_t fWritten
Number of objects written so far.
Definition TMapFile.h:48
static TMapFile * Create(const char *name, Option_t *option="READ", Int_t size=kDefaultMapSize, const char *title="")
Create a memory mapped file.
TMapRec * fLast
Last object in list of shared objects.
Definition TMapFile.h:40
Int_t fVersion
ROOT version (or -1 for shadow map file)
Definition TMapFile.h:32
Bool_t IsFolder() const override
Returns kTRUE in case object is a folder (i.e. contains browsable lists).
ULongptr_t fBaseAddr
Base address of mapped memory region.
Definition TMapFile.h:37
const char * GetName() const override
Returns name of object.
Definition TMapFile.h:94
void ls(Option_t *option="") const override
List contents of TMapFile.
TDirectory * fDirectory
Pointer to directory associated to this mapfile.
Definition TMapFile.h:42
void SumBuffer(Int_t bufsize)
Increment statistics for buffer sizes of objects in this file.
const char * GetTitle() const override
Returns title of object.
Definition TMapFile.h:97
TObject * Get(const char *name, TObject *retObj=nullptr)
Return pointer to object retrieved from shared memory.
Definition TMapFile.cxx:799
void Print(Option_t *option="") const override
Print some info about the mapped file.
char * fTitle
Title of mapped file.
Definition TMapFile.h:34
void InitDirectory()
Create the directory associated to this mapfile.
Definition TMapFile.cxx:595
void RemoveAll()
Remove all objects from shared memory.
Definition TMapFile.cxx:774
Double_t fSum2Buffer
Sum of squares of buffer sizes of objects written so far.
Definition TMapFile.h:50
Bool_t fWritable
TRUE if mapped file opened in RDWR mode.
Definition TMapFile.h:44
Longptr_t fOffset
Offset in bytes for region mapped by reader.
Definition TMapFile.h:41
void Close(Option_t *option="") override
Close a mapped file.
Definition TMapFile.cxx:978
void * OrgAddress(void *addr) const
Definition TMapFile.h:102
Bool_t cd(const char *path=nullptr)
Cd to associated directory.
void DeleteSemaphore()
Delete the semaphore.
Definition TMapFile.cxx:876
Longptr_t fSemaphore
Modification semaphore (or getpid() for WIN32)
Definition TMapFile.h:45
TList * fBrowseList
List of KeyMapFile objects.
Definition TMapFile.h:43
TMapRec * fFirst
List of streamed objects is shared memory.
Definition TMapFile.h:39
~TMapFile() override
TMapFiles may not be deleted, since we want to keep the complete TMapFile object in the mapped file f...
Definition TMapFile.cxx:559
ULongptr_t fhSemaphore
HANDLE of WIN32 Mutex object to implement semaphore.
Definition TMapFile.h:46
static void * MapToAddress()
Return the base address at which we would like the next TMapFile's mapped data to start.
void Update(TObject *obj=nullptr)
Update an object (or all objects, if obj == 0) in shared memory.
Definition TMapFile.cxx:657
TObject * fGetting
Don't deadlock in update mode, when from Get() Add() is called.
Definition TMapFile.h:47
TMapFile * FindShadowMapFile()
Returns shadow map file.
void * fMmallocDesc
Pointer to mmalloc descriptor.
Definition TMapFile.h:36
Double_t fSumBuffer
Sum of buffer sizes of objects written so far.
Definition TMapFile.h:49
static void * fgMmallocDesc
Used in Close() and operator delete()
Definition TMapFile.h:53
void CreateSemaphore(Int_t pid=0)
Create semaphore used for synchronizing access to shared memory.
Definition TMapFile.cxx:846
Longptr_t fFd
Descriptor of mapped file.
Definition TMapFile.h:31
Int_t fSize
Original start size of memory mapped region.
Definition TMapFile.h:38
TObject * Remove(TObject *obj, Bool_t lock)
Remove object from shared memory.
Definition TMapFile.cxx:698
Int_t ReleaseSemaphore()
Release semaphore. Returns 0 if OK, -1 on error.
Definition TMapFile.cxx:946
static void SetMapAddress(Longptr_t addr)
Set preferred map address.
char * fName
Name of mapped file.
Definition TMapFile.h:33
TMapFile()
Default ctor. Does not much except setting some basic values.
Definition TMapFile.cxx:210
char * fOption
Directory creation options.
Definition TMapFile.h:35
friend class TMapRec
Definition TMapFile.h:28
Int_t AcquireSemaphore()
Acquire semaphore. Returns 0 if OK, -1 on error.
Definition TMapFile.cxx:901
void Browse(TBrowser *b) override
Browse contents of TMapFile.
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:610
static Longptr_t fgMapAddress
Map to this address, set address via SetMapAddress()
Definition TMapFile.h:52
Int_t GetBestBuffer()
Return the best buffer size for objects in this file.
TMapRec * GetFirst() const
Definition TMapFile.h:98
Keep track of an object in the mapped file.
Definition TMapFile.h:133
TObject * fObject
Pointer to original object.
Definition TMapFile.h:140
Int_t fBufSize
Buffer size.
Definition TMapFile.h:142
TMapRec(const TMapRec &)=delete
char * fName
Object name.
Definition TMapFile.h:138
TMapRec * fNext
Next MapRec in list.
Definition TMapFile.h:143
TObject * GetObject() const
This method returns a pointer to the original object.
Definition TMapFile.cxx:198
char * fClassName
Class name.
Definition TMapFile.h:139
void * fBuffer
Buffer containing object of class name.
Definition TMapFile.h:141
~TMapRec()
Destructor.
Definition TMapFile.cxx:186
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:457
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:972
virtual void SysError(const char *method, const char *msgfmt,...) const
Issue system error message.
Definition TObject.cxx:1085
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1057
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
static void SetDtorOnly(void *obj)
Set destructor only flag.
Definition TObject.cxx:1177
void MakeZombie()
Definition TObject.h:53
static Bool_t HasCustomNewDelete()
return the has custom delete flag
Definition TStorage.cxx:431
static void * ReAlloc(void *vp, size_t size, size_t oldsize)
Reallocate (i.e.
Definition TStorage.cxx:182
Basic string class.
Definition TString.h:138
int CompareTo(const char *cs, ECaseCompare cmp=kExact) const
Compare a string to char *cs2.
Definition TString.cxx:464
@ kIgnoreCase
Definition TString.h:285
static void ResetErrno()
Static function resetting system error number.
Definition TSystem.cxx:282
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1285
static Int_t GetErrno()
Static function returning system error number.
Definition TSystem.cxx:274
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:1307
virtual int Unlink(const char *name)
Unlink, i.e.
Definition TSystem.cxx:1392
Abstract base class for TMapFile.
const Int_t n
Definition legend1.C:16
R__EXTERN TROOT * gROOTLocal
Definition TROOT.h:384
R__EXTERN GetMapFileMapllocDesc_t * gGetMapFileMallocDesc
Definition TStorage.h:140
R__EXTERN FreeIfTMapFile_t * gFreeIfTMapFile
Definition TStorage.h:139
R__EXTERN void * gMmallocDesc
Definition TStorage.h:141
Set ROOT::Internal::gFreeIfTMapFile on library load.
Definition TMapFile.cxx:158