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