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