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