Logo ROOT   6.10/09
Reference Guide
TThread.cxx
Go to the documentation of this file.
1 // @(#)root/thread:$Id$
2 // Author: Fons Rademakers 02/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 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TThread //
15 // //
16 // This class implements threads. A thread is an execution environment //
17 // much lighter than a process. A single process can have multiple //
18 // threads. The actual work is done via the TThreadImp class (either //
19 // TPosixThread or TWin32Thread). //
20 // //
21 //////////////////////////////////////////////////////////////////////////
22 
23 #include "RConfigure.h"
24 
25 #include "TThread.h"
26 #include "TThreadImp.h"
27 #include "TThreadFactory.h"
28 #include "TROOT.h"
29 #include "TApplication.h"
30 #include "TVirtualPad.h"
31 #include "TMethodCall.h"
32 #include "TMutex.h"
33 #include "TTimeStamp.h"
34 #include "TInterpreter.h"
35 #include "TError.h"
36 #include "Varargs.h"
37 #include "ThreadLocalStorage.h"
38 #include "TThreadSlots.h"
39 
44 char *volatile TThread::fgXAct = 0;
47 void **volatile TThread::fgXArr = 0;
48 volatile Int_t TThread::fgXAnb = 0;
49 volatile Int_t TThread::fgXArt = 0;
50 
51 static void CINT_alloc_lock() { gGlobalMutex->Lock(); }
52 static void CINT_alloc_unlock() { gGlobalMutex->UnLock(); }
53 
55 
56 static void ThreadInternalLock() { if (gMainInternalMutex) gMainInternalMutex->Lock(); }
57 static void ThreadInternalUnLock() { if (gMainInternalMutex) gMainInternalMutex->UnLock(); }
58 
59 static Bool_t fgIsTearDown(kFALSE);
60 
61 extern "C" void ROOT_TThread_Initialize()
62 {
64 };
65 
66 //------------------------------------------------------------------------------
67 
68 // Set gGlobalMutex to 0 when Thread library gets unloaded
69 class TThreadTearDownGuard {
70 public:
71  TThreadTearDownGuard() { fgIsTearDown = kFALSE; }
72  ~TThreadTearDownGuard() {
73  // Note: we could insert here a wait for all thread to be finished.
74  // this is questionable though as we need to balance between fixing a
75  // user error (the thread was let lose and the caller did not explicit wait)
76  // and the risk that we can not terminate a failing process.
77 
80  gGlobalMutex = 0;
81  delete m;
83  TThread::fgThreadImp = 0;
84  delete imp;
85  }
86 };
87 static TThreadTearDownGuard gTearDownGuard;
88 
89 //------------------------------------------------------------------------------
90 
91 class TJoinHelper {
92 private:
93  TThread *fT;
94  TThread *fH;
95  void **fRet;
96  Long_t fRc;
97  TMutex *fM;
98  TCondition *fC;
99  Bool_t fJoined;
100 
101  static void* JoinFunc(void *p);
102 
103 public:
104  TJoinHelper(TThread *th, void **ret);
105  ~TJoinHelper();
106 
107  Int_t Join();
108 };
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Constructor of Thread helper class.
112 
113 TJoinHelper::TJoinHelper(TThread *th, void **ret)
114  : fT(th), fRet(ret), fRc(0), fM(new TMutex), fC(new TCondition(fM)), fJoined(kFALSE)
115 {
116  fH = new TThread("JoinHelper", JoinFunc, this);
117 }
118 
119 ////////////////////////////////////////////////////////////////////////////////
120 /// Destructor.
121 
122 TJoinHelper::~TJoinHelper()
123 {
124  delete fC;
125  delete fM;
126  delete fH;
127 }
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 /// Static method which runs in a separate thread to handle thread
131 /// joins without blocking the main thread.
132 /// Return a value (zero) so that it makes a joinable thread.
133 
134 void* TJoinHelper::JoinFunc(void *p)
135 {
136  TJoinHelper *jp = (TJoinHelper*)p;
137 
138  jp->fRc = jp->fT->Join(jp->fRet);
139 
140  jp->fM->Lock();
141  jp->fJoined = kTRUE;
142  jp->fC->Signal();
143  jp->fM->UnLock();
144 
145  TThread::Exit(0);
146 
147  return 0;
148 }
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Thread join function.
152 
153 Int_t TJoinHelper::Join()
154 {
155  fM->Lock();
156  fH->Run();
157 
158  while (kTRUE) {
159  // TimedWaitRelative will release the mutex (i.e. equivalent to fM->Unlock),
160  // then block on the condition variable. Upon return it will lock the mutex.
161  int r = fC->TimedWaitRelative(100); // 100 ms
162 
163  // From the man page from pthread_ond_timedwait:
164 
165  // When using condition variables there is always a Boolean predicate
166  // involving shared variables associated with each condition wait that
167  // is true if the thread should proceed. Spurious wakeups from the
168  // pthread_cond_timedwait() or pthread_cond_wait() functions may occur.
169  // Since the return from pthread_cond_timedwait() or pthread_cond_wait()
170  // does not imply anything about the value of this predicate, the
171  // predicate should be re-evaluated upon such return.
172 
173  if (r == 0 || r == 1) {
174  // If we received the signal or timed out, let's check the value
175  if (fJoined) break;
176  } else {
177  // If any other error occured, there is no point in trying again
178  break;
179  }
180 
182  }
183 
184  fM->UnLock();
185 
186  // And wait for the help to finish to avoid the risk that it is still
187  // running when the main tread is finished (and the thread library unloaded!)
188  TThread::fgThreadImp->Join(fH, 0);
189 
190  return fRc;
191 }
192 
193 
194 //------------------------------------------------------------------------------
195 
197 
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Create a thread. Specify the function or static class method
201 /// to be executed by the thread and a pointer to the argument structure.
202 /// The user function should return a void*. To start the thread call Run().
203 
204 TThread::TThread(VoidRtnFunc_t fn, void *arg, EPriority pri)
205  : TNamed("<anon>", "")
206 {
207  fDetached = kFALSE;
208  fFcnVoid = 0;
209  fFcnRetn = fn;
210  fPriority = pri;
211  fThreadArg = arg;
212  Constructor();
213  fNamed = kFALSE;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Create a detached thread. Specify the function or static class method
218 /// to be executed by the thread and a pointer to the argument structure.
219 /// To start the thread call Run().
220 
221 TThread::TThread(VoidFunc_t fn, void *arg, EPriority pri)
222  : TNamed("<anon>", "")
223 {
224  fDetached = kTRUE;
225  fFcnRetn = 0;
226  fFcnVoid = fn;
227  fPriority = pri;
228  fThreadArg = arg;
229  Constructor();
230  fNamed = kFALSE;
231 }
232 
233 ////////////////////////////////////////////////////////////////////////////////
234 /// Create thread with a name. Specify the function or static class method
235 /// to be executed by the thread and a pointer to the argument structure.
236 /// The user function should return a void*. To start the thread call Run().
237 
238 TThread::TThread(const char *thname, VoidRtnFunc_t fn, void *arg,
239  EPriority pri) : TNamed(thname, "")
240 {
241  fDetached = kFALSE;
242  fFcnVoid = 0;
243  fFcnRetn = fn;
244  fPriority = pri;
245  fThreadArg = arg;
246  Constructor();
247  fNamed = kTRUE;
248 }
249 
250 ////////////////////////////////////////////////////////////////////////////////
251 /// Create a detached thread with a name. Specify the function or static
252 /// class method to be executed by the thread and a pointer to the argument
253 /// structure. To start the thread call Run().
254 
255 TThread::TThread(const char *thname, VoidFunc_t fn, void *arg,
256  EPriority pri) : TNamed(thname, "")
257 {
258  fDetached = kTRUE;
259  fFcnRetn = 0;
260  fFcnVoid = fn;
261  fPriority = pri;
262  fThreadArg = arg;
263  Constructor();
264  fNamed = kTRUE;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Create a TThread for a already running thread.
269 
271 {
272  fDetached = kTRUE;
273  fFcnRetn = 0;
274  fFcnVoid = 0;
276  fThreadArg = 0;
277  Constructor();
278 
279  // Changing the id must be protected as it will be look at by multiple
280  // threads (see TThread::GetThread)
282  fNamed = kFALSE;
283  fId = (id ? id : SelfId());
286 
287  if (gDebug)
288  Info("TThread::TThread", "TThread attached to running thread");
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 /// Initialize the Thread package. This initializes the TThread and ROOT
293 /// global mutexes to make parts of ROOT thread safe/aware. This call is
294 /// implicit in case a TThread is created.
295 
297 {
298  Init();
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Return true, if the TThread objects have been initialize. If false,
303 /// the process is (from ROOT's point of view) single threaded.
304 
306 {
307  if (fgThreadImp)
308  return kTRUE;
309  return kFALSE;
310 }
311 
312 ////////////////////////////////////////////////////////////////////////////////
313 /// Initialize global state and variables once.
314 
316 {
317  if (fgThreadImp || fgIsTearDown) return;
318 
319 #if !defined (_REENTRANT) && !defined (WIN32)
320  // Not having it means (See TVirtualMutext.h) that the LOCKGUARD macro are empty.
321  ::Fatal("Init","_REENTRANT must be #define-d for TThread to work properly.");
322 #endif
323 
325  gMainInternalMutex = new TMutex(kTRUE);
326 
328  fgMainMutex = new TMutex(kTRUE);
331 
332 
333  // Create the single global mutex
334  gGlobalMutex = new TMutex(kTRUE);
335  // We need to make sure that gCling is initialized.
338 
339  //To avoid deadlocks, gInterpreterMutex and gROOTMutex need
340  // to point at the same instance
341  {
343  if (!gInterpreterMutex) {
345  }
347  }
348 }
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// Common thread constructor.
352 
354 {
355  fHolder = 0;
356  fClean = 0;
357  fState = kNewState;
358 
359  fId = -1;
360  fHandle= 0;
361  if (!fgThreadImp) Init();
362 
363  SetComment("Constructor: MainInternalMutex Locking");
365  SetComment("Constructor: MainInternalMutex Locked");
366 
367  if (fgMain) fgMain->fPrev = this;
368  fNext = fgMain; fPrev = 0; fgMain = this;
369 
371  SetComment();
372 
373  // thread is set up in initialisation routine or Run().
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Cleanup the thread.
378 
380 {
381  if (gDebug)
382  Info("TThread::~TThread", "thread deleted");
383 
384  // Disconnect thread instance
385 
386  SetComment("Destructor: MainInternalMutex Locking");
388  SetComment("Destructor: MainInternalMutex Locked");
389 
390  if (fPrev) fPrev->fNext = fNext;
391  if (fNext) fNext->fPrev = fPrev;
392  if (fgMain == this) fgMain = fNext;
393 
395  SetComment();
396  if (fHolder) *fHolder = 0;
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Static method to delete the specified thread.
401 /// Returns -1 in case the thread was running and has been killed. Returns
402 /// 0 in case the thread has been Delete and Cleaned up. The th pointer is
403 /// not valid anymore in that case.
404 
406 {
407  if (!th) return 0;
408  th->fHolder = &th;
409 
410  if (th->fState == kRunningState) { // Cancel if running
411  th->fState = kDeletingState;
412 
413  if (gDebug)
414  th->Info("TThread::Delete", "deleting thread");
415 
416  th->Kill();
417  return -1;
418  }
419 
420  CleanUp();
421  return 0;
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 /// Static method to check if threads exist.
426 /// Returns the number of running threads.
427 
429 {
431 
432  Int_t num = 0;
433  for (TThread *l = fgMain; l; l = l->fNext)
434  num++; //count threads
435 
437 
438  return num;
439 }
440 
441 ////////////////////////////////////////////////////////////////////////////////
442 /// Set thread priority.
443 
445 {
446  fPriority = pri;
447 }
448 
449 ////////////////////////////////////////////////////////////////////////////////
450 /// Static method to find a thread by id.
451 
453 {
454  TThread *myTh;
455 
457 
458  for (myTh = fgMain; myTh && (myTh->fId != id); myTh = myTh->fNext) { }
459 
461 
462  return myTh;
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 /// Static method to find a thread by name.
467 
469 {
470  TThread *myTh;
471 
473 
474  for (myTh = fgMain; myTh && (strcmp(name, myTh->GetName())); myTh = myTh->fNext) { }
475 
477 
478  return myTh;
479 }
480 
481 ////////////////////////////////////////////////////////////////////////////////
482 /// Static method returning pointer to current thread.
483 
485 {
486  TTHREAD_TLS(TThread*) self = 0;
487 
488  if (!self || fgIsTearDown) {
489  if (fgIsTearDown) self = 0;
490  self = GetThread(SelfId());
491  }
492  return self;
493 }
494 
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// Join this thread.
498 
500 {
501  if (fId == -1) {
502  Error("Join", "thread not running");
503  return -1;
504  }
505 
506  if (fDetached) {
507  Error("Join", "cannot join detached thread");
508  return -1;
509  }
510 
511  if (SelfId() != fgMainId)
512  return fgThreadImp->Join(this, ret);
513 
514  // do not block the main thread, use helper thread
515  TJoinHelper helper(this, ret);
516 
517  return helper.Join();
518 }
519 
520 ////////////////////////////////////////////////////////////////////////////////
521 /// Static method to join a thread by id.
522 
523 Long_t TThread::Join(Long_t jid, void **ret)
524 {
525  TThread *myTh = GetThread(jid);
526 
527  if (!myTh) {
528  ::Error("TThread::Join", "cannot find thread 0x%lx", jid);
529  return -1L;
530  }
531 
532  return myTh->Join(ret);
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Static method returning the id for the current thread.
537 
539 {
540  if (fgIsTearDown) return -1;
541  if (!fgThreadImp) Init();
542 
543  return fgThreadImp->SelfId();
544 }
545 
546 ////////////////////////////////////////////////////////////////////////////////
547 /// Start the thread. This starts the static method TThread::Function()
548 /// which calls the user function specified in the TThread ctor with
549 /// the arg argument. Returns 0 on success, otherwise an error number will
550 /// be returned.
551 
552 Int_t TThread::Run(void *arg)
553 {
554  if (arg) fThreadArg = arg;
555 
556  SetComment("Run: MainInternalMutex locking");
558  SetComment("Run: MainMutex locked");
559 
560  int iret = fgThreadImp->Run(this);
561 
563 
564  if (gDebug)
565  Info("TThread::Run", "thread run requested");
566 
568  SetComment();
569  return iret;
570 }
571 
572 ////////////////////////////////////////////////////////////////////////////////
573 /// Kill this thread. Returns 0 on success, otherwise an error number will
574 /// be returned.
575 
577 {
578  if (fState != kRunningState && fState != kDeletingState) {
579  if (gDebug)
580  Warning("TThread::Kill", "thread is not running");
581  return 13;
582  } else {
584  return fgThreadImp->Kill(this);
585  }
586 }
587 
588 ////////////////////////////////////////////////////////////////////////////////
589 /// Static method to kill the thread by id. Returns 0 on success, otherwise
590 /// an error number will be returned.
591 
593 {
594  TThread *th = GetThread(id);
595  if (th) {
596  return fgThreadImp->Kill(th);
597  } else {
598  if (gDebug)
599  ::Warning("TThread::Kill(Long_t)", "thread 0x%lx not found", id);
600  return 13;
601  }
602 }
603 
604 ////////////////////////////////////////////////////////////////////////////////
605 /// Static method to kill thread by name. Returns 0 on success, otherwise
606 /// an error number will be returned.
607 
609 {
610  TThread *th = GetThread(name);
611  if (th) {
612  return fgThreadImp->Kill(th);
613  } else {
614  if (gDebug)
615  ::Warning("TThread::Kill(const char*)", "thread %s not found", name);
616  return 13;
617  }
618 }
619 
620 ////////////////////////////////////////////////////////////////////////////////
621 /// Static method to turn off thread cancellation. Returns 0 on success,
622 /// otherwise an error number will be returned.
623 
625 {
626  return fgThreadImp ? fgThreadImp->SetCancelOff() : -1;
627 }
628 
629 ////////////////////////////////////////////////////////////////////////////////
630 /// Static method to turn on thread cancellation. Returns 0 on success,
631 /// otherwise an error number will be returned.
632 
634 {
635  return fgThreadImp ? fgThreadImp->SetCancelOn() : -1;
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 /// Static method to set the cancellation response type of the calling thread
640 /// to asynchronous, i.e. cancel as soon as the cancellation request
641 /// is received.
642 
644 {
646 }
647 
648 ////////////////////////////////////////////////////////////////////////////////
649 /// Static method to set the cancellation response type of the calling thread
650 /// to deferred, i.e. cancel only at next cancellation point.
651 /// Returns 0 on success, otherwise an error number will be returned.
652 
654 {
655  return fgThreadImp ? fgThreadImp->SetCancelDeferred() : -1;
656 }
657 
658 ////////////////////////////////////////////////////////////////////////////////
659 /// Static method to set a cancellation point. Returns 0 on success, otherwise
660 /// an error number will be returned.
661 
663 {
664  return fgThreadImp ? fgThreadImp->CancelPoint() : -1;
665 }
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 /// Static method which pushes thread cleanup method on stack.
669 /// Returns 0 in case of success and -1 in case of error.
670 
671 Int_t TThread::CleanUpPush(void *free, void *arg)
672 {
673  TThread *th = Self();
674  if (th)
675  return fgThreadImp->CleanUpPush(&(th->fClean), free, arg);
676  return -1;
677 }
678 
679 ////////////////////////////////////////////////////////////////////////////////
680 /// Static method which pops thread cleanup method off stack.
681 /// Returns 0 in case of success and -1 in case of error.
682 
684 {
685  TThread *th = Self();
686  if (th)
687  return fgThreadImp->CleanUpPop(&(th->fClean), exe);
688  return -1;
689 }
690 
691 ////////////////////////////////////////////////////////////////////////////////
692 /// Static method to cleanup the calling thread.
693 
695 {
696  TThread *th = Self();
697  if (!th) return 13;
698 
699  fgThreadImp->CleanUp(&(th->fClean));
700  fgMainMutex->CleanUp();
701  if (fgXActMutex)
702  fgXActMutex->CleanUp();
703 
704  gMainInternalMutex->CleanUp();
705 
706  if (th->fHolder)
707  delete th;
708 
709  return 0;
710 }
711 
712 ////////////////////////////////////////////////////////////////////////////////
713 /// Static method which is called after the thread has been canceled.
714 
716 {
717  if (th) {
718  th->fState = kCanceledState;
719  if (gDebug)
720  th->Info("TThread::AfterCancel", "thread is canceled");
721  } else
722  ::Error("TThread::AfterCancel", "zero thread pointer passed");
723 }
724 
725 ////////////////////////////////////////////////////////////////////////////////
726 /// Static method which terminates the execution of the calling thread.
727 
729 {
730  return fgThreadImp ? fgThreadImp->Exit(ret) : -1;
731 }
732 
733 ////////////////////////////////////////////////////////////////////////////////
734 /// Static method to sleep the calling thread.
735 
737 {
738  UInt_t ms = UInt_t(secs * 1000) + UInt_t(nanos / 1000000);
739  if (gSystem) gSystem->Sleep(ms);
740  return 0;
741 }
742 
743 ////////////////////////////////////////////////////////////////////////////////
744 /// Static method to get the current time. Returns
745 /// the number of seconds.
746 
747 Int_t TThread::GetTime(ULong_t *absSec, ULong_t *absNanoSec)
748 {
749  TTimeStamp t;
750  if (absSec) *absSec = t.GetSec();
751  if (absNanoSec) *absNanoSec = t.GetNanoSec();
752  return t.GetSec();
753 }
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 /// Static method to lock the main thread mutex.
757 
759 {
760  return (fgMainMutex ? fgMainMutex->Lock() : 0);
761 }
762 
763 ////////////////////////////////////////////////////////////////////////////////
764 /// Static method to try to lock the main thread mutex.
765 
767 {
768  return (fgMainMutex ? fgMainMutex->TryLock() : 0);
769 }
770 
771 ////////////////////////////////////////////////////////////////////////////////
772 /// Static method to unlock the main thread mutex.
773 
775 {
776  return (fgMainMutex ? fgMainMutex->UnLock() : 0);
777 }
778 
779 ////////////////////////////////////////////////////////////////////////////////
780 /// Static method which is called by the system thread function and
781 /// which in turn calls the actual user function.
782 
783 void *TThread::Function(void *ptr)
784 {
785  TThread *th;
786  void *ret, *arg;
787 
789 
790  th = (TThread *)ptr;
791 
792  // Default cancel state is OFF
793  // Default cancel type is DEFERRED
794  // User can change it by call SetCancelOn() and SetCancelAsynchronous()
795  SetCancelOff();
797  CleanUpPush((void *)&AfterCancel, th); // Enable standard cancelling function
798 
799  if (gDebug)
800  th->Info("TThread::Function", "thread is running");
801 
802  arg = th->fThreadArg;
803  th->fState = kRunningState;
804 
805  if (th->fDetached) {
806  //Detached, non joinable thread
807  (th->fFcnVoid)(arg);
808  ret = 0;
809  th->fState = kFinishedState;
810  } else {
811  //UnDetached, joinable thread
812  ret = (th->fFcnRetn)(arg);
813  th->fState = kTerminatedState;
814  }
815 
816  CleanUpPop(1); // Disable standard canceling function
817 
818  if (gDebug)
819  th->Info("TThread::Function", "thread has finished");
820 
821  TThread::Exit(ret);
822 
823  return ret;
824 }
825 
826 ////////////////////////////////////////////////////////////////////////////////
827 /// Static method listing the existing threads.
828 
830 {
831  TThread *l;
832  int i;
833 
834  if (!fgMain) {
835  ::Info("TThread::Ps", "no threads have been created");
836  return;
837  }
838 
840 
841  int num = 0;
842  for (l = fgMain; l; l = l->fNext)
843  num++;
844 
845  char cbuf[256];
846  printf(" Thread State\n");
847  for (l = fgMain; l; l = l->fNext) { // loop over threads
848  memset(cbuf, ' ', sizeof(cbuf));
849  snprintf(cbuf, sizeof(cbuf), "%3d %s:0x%lx", num--, l->GetName(), l->fId);
850  i = strlen(cbuf);
851  if (i < 30)
852  cbuf[i] = ' ';
853  cbuf[30] = 0;
854  printf("%30s", cbuf);
855 
856  switch (l->fState) { // print states
857  case kNewState: printf("Idle "); break;
858  case kRunningState: printf("Running "); break;
859  case kTerminatedState: printf("Terminated "); break;
860  case kFinishedState: printf("Finished "); break;
861  case kCancelingState: printf("Canceling "); break;
862  case kCanceledState: printf("Canceled "); break;
863  case kDeletingState: printf("Deleting "); break;
864  default: printf("Invalid ");
865  }
866  if (l->fComment[0]) printf(" // %s", l->fComment);
867  printf("\n");
868  } // end of loop
869 
871 }
872 
873 ////////////////////////////////////////////////////////////////////////////////
874 /// Static method returning a pointer to thread specific data container
875 /// of the calling thread.
876 /// k should be between 0 and kMaxUserThreadSlot for user application.
877 /// (and between kMaxUserThreadSlot and kMaxThreadSlot for ROOT libraries).
878 /// See ROOT::EThreadSlotReservation
879 
880 void **TThread::Tsd(void *dflt, Int_t k)
881 {
882  if (TThread::SelfId() == fgMainId) { //Main thread
883  return (void**)dflt;
884  } else {
885  return GetTls(k);
886  }
887 }
888 
889 ////////////////////////////////////////////////////////////////////////////////
890 /// Static method that initializes the TLS array of a thread and returns the
891 /// reference to a given position in that array.
892 
894  TTHREAD_TLS_ARRAY(void*, ROOT::kMaxThreadSlot, tls);
895 
896  // In order for the thread 'gDirectory' value to be properly
897  // initialized we set it now (otherwise it defaults
898  // to zero which is 'unexpected')
899  // We initialize it to gROOT rather than gDirectory, since
900  // TFile are currently expected to not be shared by two threads.
901  if (k == ROOT::kDirectoryThreadSlot && tls[k] == nullptr)
902  tls[k] = gROOT;
903 
904  return &(tls[k]);
905 }
906 
907 ////////////////////////////////////////////////////////////////////////////////
908 /// Static method providing a thread safe printf. Appends a newline.
909 
910 void TThread::Printf(const char *va_(fmt), ...)
911 {
912  va_list ap;
913  va_start(ap,va_(fmt));
914 
915  Int_t buf_size = 2048;
916  char *buf;
917 
918 again:
919  buf = new char[buf_size];
920 
921  int n = vsnprintf(buf, buf_size, va_(fmt), ap);
922  // old vsnprintf's return -1 if string is truncated new ones return
923  // total number of characters that would have been written
924  if (n == -1 || n >= buf_size) {
925  buf_size *= 2;
926  delete [] buf;
927  goto again;
928  }
929 
930  va_end(ap);
931 
932  void *arr[2];
933  arr[1] = (void*) buf;
934  if (XARequest("PRTF", 2, arr, 0)) return;
935 
936  printf("%s\n", buf);
937  fflush(stdout);
938 
939  delete [] buf;
940 }
941 
942 ////////////////////////////////////////////////////////////////////////////////
943 /// Thread specific error handler function.
944 /// It calls the user set error handler in the main thread.
945 
946 void TThread::ErrorHandler(int level, const char *location, const char *fmt,
947  va_list ap) const
948 {
949  Int_t buf_size = 2048;
950  char *buf, *bp;
951 
952 again:
953  buf = new char[buf_size];
954 
955  int n = vsnprintf(buf, buf_size, fmt, ap);
956  // old vsnprintf's return -1 if string is truncated new ones return
957  // total number of characters that would have been written
958  if (n == -1 || n >= buf_size) {
959  buf_size *= 2;
960  delete [] buf;
961  goto again;
962  }
963  if (level >= kSysError && level < kFatal) {
964  char *buf1 = new char[buf_size + strlen(gSystem->GetError()) + 5];
965  sprintf(buf1, "%s (%s)", buf, gSystem->GetError());
966  bp = buf1;
967  delete [] buf;
968  } else
969  bp = buf;
970 
971  void *arr[4];
972  arr[1] = (void*) Long_t(level);
973  arr[2] = (void*) location;
974  arr[3] = (void*) bp;
975  if (XARequest("ERRO", 4, arr, 0)) return;
976 
977  if (level != kFatal)
978  ::GetErrorHandler()(level, level >= gErrorAbortLevel, location, bp);
979  else
980  ::GetErrorHandler()(level, kTRUE, location, bp);
981 
982  delete [] bp;
983 }
984 
985 ////////////////////////////////////////////////////////////////////////////////
986 /// Interface to ErrorHandler. User has to specify the class name as
987 /// part of the location, just like for the global Info(), Warning() and
988 /// Error() functions.
989 
990 void TThread::DoError(int level, const char *location, const char *fmt,
991  va_list va) const
992 {
993  char *loc = 0;
994 
995  if (location) {
996  loc = new char[strlen(location) + strlen(GetName()) + 32];
997  sprintf(loc, "%s %s:0x%lx", location, GetName(), fId);
998  } else {
999  loc = new char[strlen(GetName()) + 32];
1000  sprintf(loc, "%s:0x%lx", GetName(), fId);
1001  }
1002 
1003  ErrorHandler(level, loc, fmt, va);
1004 
1005  delete [] loc;
1006 }
1007 
1008 ////////////////////////////////////////////////////////////////////////////////
1009 /// Static method used to allow commands to be executed by the main thread.
1010 
1011 Int_t TThread::XARequest(const char *xact, Int_t nb, void **ar, Int_t *iret)
1012 {
1013  if (!gApplication || !gApplication->IsRunning()) return 0;
1014 
1015  // The first time, create the related static vars
1016  if (!fgXActMutex && gGlobalMutex) {
1017  gGlobalMutex->Lock();
1018  if (!fgXActMutex) {
1019  fgXActMutex = new TMutex(kTRUE);
1020  fgXActCondi = new TCondition;
1021  new TThreadTimer;
1022  }
1023  gGlobalMutex->UnLock();
1024  }
1025 
1026  TThread *th = Self();
1027  if (th && th->fId != fgMainId) { // we are in the thread
1028  th->SetComment("XARequest: XActMutex Locking");
1029  fgXActMutex->Lock();
1030  th->SetComment("XARequest: XActMutex Locked");
1031 
1033  TMutexImp *condmutex = fgXActCondi->GetMutex()->fMutexImp;
1034 
1035  // Lock now, so the XAction signal will wait
1036  // and never come before the wait
1037  condmutex->Lock();
1038 
1039  fgXAnb = nb;
1040  fgXArr = ar;
1041  fgXArt = 0;
1042  fgXAct = (char*) xact;
1043  th->SetComment(fgXAct);
1044 
1045  if (condimp) condimp->Wait();
1046  condmutex->UnLock();
1047 
1048  if (iret) *iret = fgXArt;
1049  fgXActMutex->UnLock();
1050  th->SetComment();
1051  return 1997;
1052  } else //we are in the main thread
1053  return 0;
1054 }
1055 
1056 ////////////////////////////////////////////////////////////////////////////////
1057 /// Static method called via the thread timer to execute in the main
1058 /// thread certain commands. This to avoid sophisticated locking and
1059 /// possible deadlocking.
1060 
1062 {
1064  TMutexImp *condmutex = fgXActCondi->GetMutex()->fMutexImp;
1065  condmutex->Lock();
1066 
1067  char const acts[] = "PRTF CUPD CANV CDEL PDCD METH ERRO";
1068  enum { kPRTF = 0, kCUPD = 5, kCANV = 10, kCDEL = 15,
1069  kPDCD = 20, kMETH = 25, kERRO = 30 };
1070  int iact = strstr(acts, fgXAct) - acts;
1071  char *cmd = 0;
1072 
1073  switch (iact) {
1074 
1075  case kPRTF:
1076  printf("%s\n", (const char*)fgXArr[1]);
1077  fflush(stdout);
1078  break;
1079 
1080  case kERRO:
1081  {
1082  int level = (int)Long_t(fgXArr[1]);
1083  const char *location = (const char*)fgXArr[2];
1084  char *mess = (char*)fgXArr[3];
1085  if (level != kFatal)
1086  GetErrorHandler()(level, level >= gErrorAbortLevel, location, mess);
1087  else
1088  GetErrorHandler()(level, kTRUE, location, mess);
1089  delete [] mess;
1090  }
1091  break;
1092 
1093  case kCUPD:
1094  //((TCanvas *)fgXArr[1])->Update();
1095  union CastFromFuncToVoidPtr_t {
1096  void (*fFuncPtr)(void*);
1097  void* fVoidPtr;
1098  } castFromFuncToVoidPtr;
1099  castFromFuncToVoidPtr.fVoidPtr = fgXArr[2];
1100  (*castFromFuncToVoidPtr.fFuncPtr)(fgXArr[1]); // aka TCanvas::Update()
1101  break;
1102 
1103  case kCANV:
1104 
1105  switch(fgXAnb) { // Over TCanvas constructors
1106 
1107  case 2:
1108  //((TCanvas*)fgXArr[1])->Constructor();
1109  cmd = Form("((TCanvas *)0x%lx)->Constructor();",(Long_t)fgXArr[1]);
1110  gROOT->ProcessLine(cmd);
1111  break;
1112 
1113  case 5:
1114  //((TCanvas*)fgXArr[1])->Constructor(
1115  // (char*)fgXArr[2],
1116  // (char*)fgXArr[3],
1117  // *((Int_t*)(fgXArr[4])));
1118  cmd = Form("((TCanvas *)0x%lx)->Constructor((char*)0x%lx,(char*)0x%lx,*((Int_t*)(0x%lx)));",(Long_t)fgXArr[1],(Long_t)fgXArr[2],(Long_t)fgXArr[3],(Long_t)fgXArr[4]);
1119  gROOT->ProcessLine(cmd);
1120  break;
1121  case 6:
1122  //((TCanvas*)fgXArr[1])->Constructor(
1123  // (char*)fgXArr[2],
1124  // (char*)fgXArr[3],
1125  // *((Int_t*)(fgXArr[4])),
1126  // *((Int_t*)(fgXArr[5])));
1127  cmd = Form("((TCanvas *)0x%lx)->Constructor((char*)0x%lx,(char*)0x%lx,*((Int_t*)(0x%lx)),*((Int_t*)(0x%lx)));",(Long_t)fgXArr[1],(Long_t)fgXArr[2],(Long_t)fgXArr[3],(Long_t)fgXArr[4],(Long_t)fgXArr[5]);
1128  gROOT->ProcessLine(cmd);
1129  break;
1130 
1131  case 8:
1132  //((TCanvas*)fgXArr[1])->Constructor(
1133  // (char*)fgXArr[2],
1134  // (char*)fgXArr[3],
1135  // *((Int_t*)(fgXArr[4])),
1136  // *((Int_t*)(fgXArr[5])),
1137  // *((Int_t*)(fgXArr[6])),
1138  // *((Int_t*)(fgXArr[7])));
1139  cmd = Form("((TCanvas *)0x%lx)->Constructor((char*)0x%lx,(char*)0x%lx,*((Int_t*)(0x%lx)),*((Int_t*)(0x%lx)),*((Int_t*)(0x%lx)),*((Int_t*)(0x%lx)));",(Long_t)fgXArr[1],(Long_t)fgXArr[2],(Long_t)fgXArr[3],(Long_t)fgXArr[4],(Long_t)fgXArr[5],(Long_t)fgXArr[6],(Long_t)fgXArr[7]);
1140  gROOT->ProcessLine(cmd);
1141  break;
1142 
1143  }
1144  break;
1145 
1146  case kCDEL:
1147  //((TCanvas*)fgXArr[1])->Destructor();
1148  cmd = Form("((TCanvas *)0x%lx)->Destructor();",(Long_t)fgXArr[1]);
1149  gROOT->ProcessLine(cmd);
1150  break;
1151 
1152  case kPDCD:
1153  ((TVirtualPad*) fgXArr[1])->Divide( *((Int_t*)(fgXArr[2])),
1154  *((Int_t*)(fgXArr[3])),
1155  *((Float_t*)(fgXArr[4])),
1156  *((Float_t*)(fgXArr[5])),
1157  *((Int_t*)(fgXArr[6])));
1158  break;
1159  case kMETH:
1160  ((TMethodCall *) fgXArr[1])->Execute((void*)(fgXArr[2]),(const char*)(fgXArr[3]));
1161  break;
1162 
1163  default:
1164  ::Error("TThread::XAction", "wrong case");
1165  }
1166 
1167  fgXAct = 0;
1168  if (condimp) condimp->Signal();
1169  condmutex->UnLock();
1170 }
1171 
1172 
1173 //////////////////////////////////////////////////////////////////////////
1174 // //
1175 // TThreadTimer //
1176 // //
1177 //////////////////////////////////////////////////////////////////////////
1178 
1179 ////////////////////////////////////////////////////////////////////////////////
1180 /// Create thread timer.
1181 
1183 {
1184  gSystem->AddTimer(this);
1185 }
1186 
1187 ////////////////////////////////////////////////////////////////////////////////
1188 /// Periodically execute the TThread::XAxtion() method in the main thread.
1189 
1191 {
1192  if (TThread::fgXAct) { TThread::XAction(); }
1193  Reset();
1194 
1195  return kFALSE;
1196 }
1197 
1198 
1199 //////////////////////////////////////////////////////////////////////////
1200 // //
1201 // TThreadCleaner //
1202 // //
1203 //////////////////////////////////////////////////////////////////////////
1204 
1205 ////////////////////////////////////////////////////////////////////////////////
1206 /// Call user clean up routines.
1207 
1209 {
1210  TThread::CleanUp();
1211 }
static void ** GetTls(Int_t k)
Static method that initializes the TLS array of a thread and returns the reference to a given positio...
Definition: TThread.cxx:893
static void AfterCancel(TThread *th)
Static method which is called after the thread has been canceled.
Definition: TThread.cxx:715
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
static Int_t SetCancelDeferred()
Static method to set the cancellation response type of the calling thread to deferred, i.e.
Definition: TThread.cxx:653
virtual Int_t Wait()=0
static void ThreadInternalUnLock()
Definition: TThread.cxx:57
Definition: TMutex.h:30
void *(* VoidRtnFunc_t)(void *)
Definition: TThread.h:49
static Bool_t IsInitialized()
Return true, if the TThread objects have been initialize.
Definition: TThread.cxx:305
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:423
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:847
virtual TVirtualMutex * Factory(Bool_t=kFALSE)=0
friend class TJoinHelper
Definition: TThread.h:45
static void XAction()
Static method called via the thread timer to execute in the main thread certain commands.
Definition: TThread.cxx:1061
virtual Int_t Join(TThread *th, void **ret)=0
virtual Int_t UnLock()=0
static TCondition * fgXActCondi
Definition: TThread.h:96
void Reset()
Reset the timer.
Definition: TTimer.cxx:157
friend class TThreadTimer
Definition: TThread.h:41
static TThread * fgMain
Definition: TThread.h:93
float Float_t
Definition: RtypesCore.h:53
static void Initialize()
Initialize the Thread package.
Definition: TThread.cxx:296
RooArgList L(const RooAbsArg &v1)
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
void Constructor()
Common thread constructor.
Definition: TThread.cxx:353
void * fThreadArg
Definition: TThread.h:83
static Int_t SetCancelOff()
Static method to turn off thread cancellation.
Definition: TThread.cxx:624
virtual Long_t SelfId()=0
This class implements a mutex interface.
Definition: TVirtualMutex.h:32
#define gROOT
Definition: TROOT.h:375
static void Printf(const char *fmt,...)
Static method providing a thread safe printf. Appends a newline.
Definition: TThread.cxx:910
R__EXTERN Int_t gErrorAbortLevel
Definition: TError.h:106
static Int_t SetCancelOn()
Static method to turn on thread cancellation.
Definition: TThread.cxx:633
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
time_t GetSec() const
Definition: TTimeStamp.h:135
static TThreadImp * fgThreadImp
Definition: TThread.h:87
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
TThread * fPrev
Definition: TThread.h:72
R__EXTERN TThreadFactory * gThreadFactory
static Int_t TryLock()
Static method to try to lock the main thread mutex.
Definition: TThread.cxx:766
EState fState
Definition: TThread.h:75
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
virtual Int_t CleanUpPush(void **main, void *free, void *arg)=0
R__EXTERN void **(* gThreadTsd)(void *, Int_t)
Definition: TThreadSlots.h:40
Int_t UnLock()
Unlock the mutex.
Definition: TMutex.cxx:68
virtual TThreadImp * CreateThreadImp()=0
static Int_t CleanUpPop(Int_t exe=0)
Static method which pops thread cleanup method off stack.
Definition: TThread.cxx:683
Long_t fHandle
Definition: TThread.h:78
static volatile Int_t fgXArt
Definition: TThread.h:91
TThread(const TThread &)
virtual Int_t Lock()=0
virtual Int_t CleanUp(void **main)=0
static Int_t SetCancelAsynchronous()
Static method to set the cancellation response type of the calling thread to asynchronous, i.e.
Definition: TThread.cxx:643
static void CINT_alloc_unlock()
Definition: TThread.cxx:52
void SetComment(const char *txt=0)
Definition: TThread.h:100
R__EXTERN Int_t(* gThreadXAR)(const char *xact, Int_t nb, void **ar, Int_t *iret)
Definition: TVirtualPad.h:286
const Int_t kSysError
Definition: TError.h:41
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition: TSystem.cxx:444
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
const Int_t kFatal
Definition: TError.h:42
~TThreadCleaner()
Call user clean up routines.
Definition: TThread.cxx:1208
virtual Int_t Lock()=0
static Int_t XARequest(const char *xact, Int_t nb, void **ar, Int_t *iret)
Static method used to allow commands to be executed by the main thread.
Definition: TThread.cxx:1011
virtual Int_t SetCancelDeferred()=0
static Long_t SelfId()
Static method returning the id for the current thread.
Definition: TThread.cxx:538
#define va_(arg)
Definition: Varargs.h:41
Method or function calling interface.
Definition: TMethodCall.h:37
Int_t Run(void *arg=0)
Start the thread.
Definition: TThread.cxx:552
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition: TVirtualPad.h:49
void Error(const char *location, const char *msgfmt,...)
VoidFunc_t fFcnVoid
Definition: TThread.h:82
R__EXTERN TVirtualMutex * gGlobalMutex
Definition: TVirtualMutex.h:27
virtual ~TThread()
Cleanup the thread.
Definition: TThread.cxx:379
static TThread * GetThread(Long_t id)
Static method to find a thread by id.
Definition: TThread.cxx:452
virtual Int_t SetCancelOff()=0
EPriority fPriority
Definition: TThread.h:74
static TMutex * fgMainMutex
Definition: TThread.h:94
TRandom2 r(17)
static Int_t Exists()
Static method to check if threads exist.
Definition: TThread.cxx:428
R__EXTERN TSystem * gSystem
Definition: TSystem.h:539
static void Init()
Initialize global state and variables once.
Definition: TThread.cxx:315
TMutexImp * fMutexImp
Definition: TMutex.h:36
TConditionImp * fConditionImp
Definition: TCondition.h:37
TMutex * GetMutex() const
Get internally created mutex.
Definition: TCondition.cxx:65
virtual Int_t UnLock()=0
static char *volatile fgXAct
Definition: TThread.h:88
void DoError(Int_t level, const char *location, const char *fmt, va_list va) const
Interface to ErrorHandler.
Definition: TThread.cxx:990
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual Int_t Run(TThread *th)=0
TMarker * m
Definition: textangle.C:8
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
char * Form(const char *fmt,...)
TLine * l
Definition: textangle.C:4
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:51
static Long_t fgMainId
Definition: TThread.h:92
static Int_t CleanUpPush(void *free, void *arg=0)
Static method which pushes thread cleanup method on stack.
Definition: TThread.cxx:671
static Int_t CancelPoint()
Static method to set a cancellation point.
Definition: TThread.cxx:662
Long_t Join(void **ret=0)
Join this thread.
Definition: TThread.cxx:499
virtual Int_t SetCancelAsynchronous()=0
Int_t Kill()
Kill this thread.
Definition: TThread.cxx:576
Int_t CleanUp()
Clean up of mutex.
Definition: TMutex.cxx:76
static Int_t Lock()
Static method to lock the main thread mutex.
Definition: TThread.cxx:758
VoidRtnFunc_t fFcnRetn
Definition: TThread.h:81
static TInterpreter * Instance()
returns gInterpreter global
Int_t TryLock()
Try to lock mutex.
Definition: TMutex.cxx:57
static void Ps()
Static method listing the existing threads.
Definition: TThread.cxx:829
static TMutex * fgXActMutex
Definition: TThread.h:95
Bool_t Notify()
Periodically execute the TThread::XAxtion() method in the main thread.
Definition: TThread.cxx:1190
const Bool_t kFALSE
Definition: RtypesCore.h:92
static void **volatile fgXArr
Definition: TThread.h:89
static Bool_t fgIsTearDown(kFALSE)
static Int_t CleanUp()
Static method to cleanup the calling thread.
Definition: TThread.cxx:694
long Long_t
Definition: RtypesCore.h:50
virtual Int_t SetCancelOn()=0
static void ** Tsd(void *dflt, Int_t k)
Static method returning a pointer to thread specific data container of the calling thread...
Definition: TThread.cxx:880
static Int_t UnLock()
Static method to unlock the main thread mutex.
Definition: TThread.cxx:774
EPriority
Definition: TThread.h:52
#define ClassImp(name)
Definition: Rtypes.h:336
virtual void SetAlloclockfunc(void(*)()) const
Definition: TInterpreter.h:216
static TThread * Self()
Static method returning pointer to current thread.
Definition: TThread.cxx:484
TThreadTimer(Long_t ms=kItimerResolution+10)
Create thread timer.
Definition: TThread.cxx:1182
#define free
Definition: civetweb.c:821
unsigned long ULong_t
Definition: RtypesCore.h:51
The TTimeStamp encapsulates seconds and ns since EPOCH.
Definition: TTimeStamp.h:71
void SetPriority(EPriority pri)
Set thread priority.
Definition: TThread.cxx:444
static void CINT_alloc_lock()
Definition: TThread.cxx:51
Long_t fId
Definition: TThread.h:77
static RooMathCoreReg dummy
virtual Int_t Exit(void *ret)=0
Int_t Lock()
Lock the mutex.
Definition: TMutex.cxx:46
void * fClean
Definition: TThread.h:84
#define R__LOCKGUARD(mutex)
char fComment[100]
Definition: TThread.h:85
virtual Int_t CancelPoint()=0
static Int_t GetTime(ULong_t *absSec, ULong_t *absNanoSec)
Static method to get the current time.
Definition: TThread.cxx:747
virtual Int_t Kill(TThread *th)=0
void ROOT_TThread_Initialize()
Definition: TThread.cxx:61
Bool_t fDetached
Definition: TThread.h:79
typedef void((*Func_t)())
virtual Int_t Signal()=0
Bool_t fNamed
Definition: TThread.h:80
static Int_t Exit(void *ret=0)
Static method which terminates the execution of the calling thread.
Definition: TThread.cxx:728
ErrorHandlerFunc_t GetErrorHandler()
Returns the current error handler function.
Definition: TError.cxx:116
virtual void AddTimer(TTimer *t)
Add timer to list of system timers.
Definition: TSystem.cxx:478
static TThreadTearDownGuard gTearDownGuard
Definition: TThread.cxx:87
virtual void SetAllocunlockfunc(void(*)()) const
Definition: TInterpreter.h:217
void(* VoidFunc_t)(void *)
Definition: TThread.h:50
TThread * fNext
Definition: TThread.h:71
static TMutex * gMainInternalMutex
Definition: TThread.cxx:54
#define snprintf
Definition: civetweb.c:822
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
virtual Int_t CleanUpPop(void **main, Int_t exe)=0
static Int_t Sleep(ULong_t secs, ULong_t nanos=0)
Static method to sleep the calling thread.
Definition: TThread.cxx:736
Bool_t IsRunning() const
Definition: TApplication.h:147
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:901
R__EXTERN TInterpreter * gCling
Definition: TInterpreter.h:501
const Bool_t kTRUE
Definition: RtypesCore.h:91
TThread ** fHolder
Definition: TThread.h:73
const Int_t n
Definition: legend1.C:16
Int_t GetNanoSec() const
Definition: TTimeStamp.h:136
static void ThreadInternalLock()
Definition: TThread.cxx:56
virtual const char * GetError()
Return system error string.
Definition: TSystem.cxx:257
void ErrorHandler(int level, const char *location, const char *fmt, va_list ap) const
Thread specific error handler function.
Definition: TThread.cxx:946
static void * Function(void *ptr)
Static method which is called by the system thread function and which in turn calls the actual user f...
Definition: TThread.cxx:783
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:859
static volatile Int_t fgXAnb
Definition: TThread.h:90
void Delete(Option_t *option="")
Delete this object.
Definition: TThread.h:124