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