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