Logo ROOT   6.16/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
45char *volatile TThread::fgXAct = 0;
48void **volatile TThread::fgXArr = 0;
49volatile Int_t TThread::fgXAnb = 0;
50volatile Int_t TThread::fgXArt = 0;
51
52static void CINT_alloc_lock() { gGlobalMutex->Lock(); }
54
56
59
61
62extern "C" void ROOT_TThread_Initialize()
63{
65};
66
67//------------------------------------------------------------------------------
68
69// Set gGlobalMutex to 0 when Thread library gets unloaded
70class TThreadTearDownGuard {
71public:
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};
88static TThreadTearDownGuard gTearDownGuard;
89
90//------------------------------------------------------------------------------
91
92class TJoinHelper {
93private:
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
104public:
105 TJoinHelper(TThread *th, void **ret);
106 ~TJoinHelper();
107
108 Int_t Join();
109};
110
111////////////////////////////////////////////////////////////////////////////////
112/// Constructor of Thread helper class.
113
114TJoinHelper::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
123TJoinHelper::~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
135void* 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
154Int_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!)
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
205TThread::TThread(VoidRtnFunc_t fn, void *arg, EPriority pri)
206 : TNamed("<anon>", "")
207{
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
222TThread::TThread(VoidFunc_t fn, void *arg, EPriority pri)
223 : TNamed("<anon>", "")
224{
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
239TThread::TThread(const char *thname, VoidRtnFunc_t fn, void *arg,
240 EPriority pri) : TNamed(thname, "")
241{
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
256TThread::TThread(const char *thname, VoidFunc_t fn, void *arg,
257 EPriority pri) : TNamed(thname, "")
258{
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{
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).
328
331
333 fgMainMutex = new TMutex(kTRUE);
336
337
338 // Create the single global mutex
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;
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
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
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
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{
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{
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
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));
710 if (fgXActMutex)
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) {
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
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
792void *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;
819 } else {
820 //UnDetached, joinable thread
821 ret = (th->fFcnRetn)(arg);
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
889void **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
919void 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
927again:
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
955void 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
961again:
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
999void 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
1020Int_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 }
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;
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{
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{
1220}
ROOT::R::TRInterface & r
Definition: Object.C:4
static RooMathCoreReg dummy
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
float Float_t
Definition: RtypesCore.h:53
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:363
R__EXTERN Int_t gDebug
Definition: Rtypes.h:90
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
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
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
R__EXTERN TInterpreter * gCling
Definition: TInterpreter.h:540
R__EXTERN TVirtualMutex * gROOTMutex
Definition: TROOT.h:57
#define gROOT
Definition: TROOT.h:410
char * Form(const char *fmt,...)
typedef void((*Func_t)())
R__EXTERN TSystem * gSystem
Definition: TSystem.h:540
R__EXTERN TThreadFactory * gThreadFactory
R__EXTERN void **(* gThreadTsd)(void *, Int_t)
Definition: TThreadSlots.h:40
static TMutex * gMainInternalMutex
Definition: TThread.cxx:55
static void ThreadInternalUnLock()
Definition: TThread.cxx:58
static void CINT_alloc_lock()
Definition: TThread.cxx:52
static TThreadTearDownGuard gTearDownGuard
Definition: TThread.cxx:88
static Bool_t fgIsTearDown(kFALSE)
static void ThreadInternalLock()
Definition: TThread.cxx:57
void ROOT_TThread_Initialize()
Definition: TThread.cxx:62
static void CINT_alloc_unlock()
Definition: TThread.cxx:53
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:288
#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:147
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:246
virtual void SetAlloclockfunc(void(*)()) const
Definition: TInterpreter.h:245
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:866
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition: TObject.cxx:908
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
virtual void AddTimer(TTimer *t)
Add timer to list of system timers.
Definition: TSystem.cxx:480
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition: TSystem.cxx:446
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:425
virtual const char * GetError()
Return system error string.
Definition: TSystem.cxx:259
~TThreadCleaner()
Call user clean up routines.
Definition: TThread.cxx:1217
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:1191
Bool_t Notify()
Periodically execute the TThread::XAxtion() method in the main thread.
Definition: TThread.cxx:1199
VoidRtnFunc_t fFcnRetn
Definition: TThread.h:81
static TThread * GetThread(Long_t id)
Static method to find a thread by id.
Definition: TThread.cxx:461
static Int_t CleanUpPop(Int_t exe=0)
Static method which pops thread cleanup method off stack.
Definition: TThread.cxx:692
static char *volatile fgXAct
Definition: TThread.h:88
static Int_t CancelPoint()
Static method to set a cancellation point.
Definition: TThread.cxx:671
static Int_t Sleep(ULong_t secs, ULong_t nanos=0)
Static method to sleep the calling thread.
Definition: TThread.cxx:745
static void **volatile fgXArr
Definition: TThread.h:89
static Int_t TryLock()
Static method to try to lock the main thread mutex.
Definition: TThread.cxx:775
void SetPriority(EPriority pri)
Set thread priority.
Definition: TThread.cxx:453
static Int_t Exists()
Static method to check if threads exist.
Definition: TThread.cxx:437
TThread * fPrev
Definition: TThread.h:72
static void Ps()
Static method listing the existing threads.
Definition: TThread.cxx:838
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 TThreadImp * fgThreadImp
Definition: TThread.h:87
static Int_t UnLock()
Static method to unlock the main thread mutex.
Definition: TThread.cxx:783
Int_t Kill()
Kill this thread.
Definition: TThread.cxx:585
static TMutex * fgMainMutex
Definition: TThread.h:94
EState fState
Definition: TThread.h:75
static volatile Int_t fgXAnb
Definition: TThread.h:90
Long_t fHandle
Definition: TThread.h:78
static Long_t fgMainId
Definition: TThread.h:92
static void XAction()
Static method called via the thread timer to execute in the main thread certain commands.
Definition: TThread.cxx:1070
virtual ~TThread()
Cleanup the thread.
Definition: TThread.cxx:388
Bool_t fDetached
Definition: TThread.h:79
static Int_t SetCancelAsynchronous()
Static method to set the cancellation response type of the calling thread to asynchronous,...
Definition: TThread.cxx:652
static Int_t CleanUp()
Static method to cleanup the calling thread.
Definition: TThread.cxx:703
void ErrorHandler(int level, const char *location, const char *fmt, va_list ap) const
Thread specific error handler function.
Definition: TThread.cxx:955
static Int_t GetTime(ULong_t *absSec, ULong_t *absNanoSec)
Static method to get the current time.
Definition: TThread.cxx:756
static Long_t SelfId()
Static method returning the id for the current thread.
Definition: TThread.cxx:547
void Constructor()
Common thread constructor.
Definition: TThread.cxx:362
static Int_t SetCancelOn()
Static method to turn on thread cancellation.
Definition: TThread.cxx:642
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
void DoError(Int_t level, const char *location, const char *fmt, va_list va) const
Interface to ErrorHandler.
Definition: TThread.cxx:999
Long_t fId
Definition: TThread.h:77
static Int_t CleanUpPush(void *free, void *arg=0)
Static method which pushes thread cleanup method on stack.
Definition: TThread.cxx:680
Bool_t fNamed
Definition: TThread.h:80
static volatile Int_t fgXArt
Definition: TThread.h:91
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
VoidFunc_t fFcnVoid
Definition: TThread.h:82
Long_t Join(void **ret=0)
Join this thread.
Definition: TThread.cxx:508
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
EPriority fPriority
Definition: TThread.h:74
static void Printf(const char *fmt,...)
Static method providing a thread safe printf. Appends a newline.
Definition: TThread.cxx:919
static Int_t Lock()
Static method to lock the main thread mutex.
Definition: TThread.cxx:767
@ kRunningState
Definition: TThread.h:61
@ kNewState
Definition: TThread.h:60
@ kCanceledState
Definition: TThread.h:66
@ kCancelingState
Definition: TThread.h:65
@ kFinishedState
Definition: TThread.h:64
@ kTerminatedState
Definition: TThread.h:62
@ kDeletingState
Definition: TThread.h:67
@ kInvalidState
Definition: TThread.h:59
friend class TThreadTimer
Definition: TThread.h:41
static Int_t SetCancelOff()
Static method to turn off thread cancellation.
Definition: TThread.cxx:633
static void Init()
Initialize global state and variables once.
Definition: TThread.cxx:316
static Int_t SetCancelDeferred()
Static method to set the cancellation response type of the calling thread to deferred,...
Definition: TThread.cxx:662
static void AfterCancel(TThread *th)
Static method which is called after the thread has been canceled.
Definition: TThread.cxx:724
static TThread * fgMain
Definition: TThread.h:93
static TMutex * fgXActMutex
Definition: TThread.h:95
EPriority
Definition: TThread.h:52
@ kNormalPriority
Definition: TThread.h:54
static Bool_t IsInitialized()
Return true, if the TThread objects have been initialize.
Definition: TThread.cxx:306
static TThread * Self()
Static method returning pointer to current thread.
Definition: TThread.cxx:493
TThread(const TThread &)
static void Initialize()
Initialize the Thread package.
Definition: TThread.cxx:297
void SetComment(const char *txt=0)
Definition: TThread.h:100
void * fClean
Definition: TThread.h:84
static TCondition * fgXActCondi
Definition: TThread.h:96
friend class TJoinHelper
Definition: TThread.h:45
void Delete(Option_t *option="")
Delete this object.
Definition: TThread.h:124
static Int_t Exit(void *ret=0)
Static method which terminates the execution of the calling thread.
Definition: TThread.cxx:737
TThread ** fHolder
Definition: TThread.h:73
TThread * fNext
Definition: TThread.h:71
Int_t Run(void *arg=0)
Start the thread.
Definition: TThread.cxx:561
void * fThreadArg
Definition: TThread.h:83
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:50
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:519
static constexpr double ms
auto * m
Definition: textangle.C:8
auto * l
Definition: textangle.C:4