GSI Object Oriented Online Offline (Go4)  GO4-6.3.0
TGo4Thread.cxx
Go to the documentation of this file.
1 // $Id$
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 #include "TGo4Thread.h"
15 
16 #include "TThread.h"
17 #include "TSystem.h"
18 #include "TCondition.h"
19 
20 #include "TGo4Runnable.h"
21 #include "TGo4Log.h"
22 #include "Go4Exceptions.h"
23 
25  :TNamed(right)
26 {
27  GO4TRACE((14,"TGo4Thread::TGo4Thread() copy constructor",__LINE__, __FILE__));
28  fxRunnable = right.fxRunnable;
29  fbIsInternal = right.fbIsInternal;
30  fxCondition = new TCondition();
31 }
32 
33 TGo4Thread::TGo4Thread (const char *name, TGo4Runnable *runnable, Bool_t internal)
34  :TNamed(name,"This is a TGo4Thread"),
35  fbIsCreated(kFALSE),
36  fbIsRunning(kFALSE),
37  fiThreadPID(0),
38  fiThreadSelfID(0),
39  fbIsWaiting(kFALSE),
40  fxThread(nullptr)
41 {
42  GO4TRACE((14,"TGo4Thread::TGo4Thread(const char*, TGo4Runnable *, Bool_t) constructor",__LINE__, __FILE__));
43 
44  TGo4Log::Debug(" New Go4Thread ``%s'' created ",name);
45  fxRunnable = runnable;
46  fbIsInternal = internal;
47  fxCondition = new TCondition();
48  fxRunnable->SetThread(this);
49 }
50 
51 
53 {
54  GO4TRACE((14,"TGo4Thread::~TGo4Thread() destructor",__LINE__, __FILE__));
55 
56  Stop();
57  Cancel();
58  delete fxCondition;
59  fxCondition = nullptr;
60  if(fbIsInternal)
61  {
62  GO4TRACE((14,"TGo4Thread::~TGo4Thread() internal mode",__LINE__, __FILE__));
63  TGo4Log::Debug(" Go4Thread ``%s'' deleting runnable ``%s'' ",
64  GetName(),fxRunnable->GetName());
65  delete fxRunnable; // internal mode: go4thread responsible for runnable
66  }
67  else
68  {
69  GO4TRACE((14,"TGo4Thread::~TGo4Thread() non internal mode",__LINE__, __FILE__));
70  // do nothing
71  }
72 
73 }
74 
75 void TGo4Thread::Threadfunc(void *arg)
76 {
77  GO4TRACE((2,"TGo4Thread::Threadfunc(void *)",__LINE__, __FILE__));
78  TGo4Thread *go4th = (TGo4Thread *) arg; // we need reference to calling class instance
79  TGo4Runnable *runnable = go4th->GetRunnable();
80 
81  // this is the function running as pthread...
82  // initializations:
83  go4th->SetPID();
84  go4th->SetSelfID();
85 // fiThreadPID=gSystem->GetPid(); // set ids
86 // fiThreadSelfID=TThread::SelfId();
87  TGo4Log::Debug(" TThread %ld (PID:%d) of Go4Thread ``%s'' started... \n",
88  go4th->GetSelfID(), go4th->GetPID(), go4th->GetName());
89 
90 for(;;) // loop keeps thread alive after exception has occured...
91  {
92  try
93  {
94  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) try block",__LINE__, __FILE__));
95  while(1)
96  {
97  TThread::CancelPoint();
98  if( !(go4th->IsRunning()) )
99  {
100  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) waiting mode",__LINE__, __FILE__));
101  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) waiting...\n",
102  go4th->GetName(), go4th->GetPID());
103  go4th->SetWaiting(kTRUE);
104  go4th->GetCondition()->Wait(); //wait for funcrun condition
105  go4th->SetWaiting(kFALSE);
106  TGo4Log::Debug(" Go4Thread ``%s'' (PID:%d) running...\n",
107  go4th->GetName(), go4th->GetPID() );
108  }
109  else
110  {
111  // Do Nothing, just continue
112  }
113 
114  if(go4th->IsCreated())
115  // normal mode: enter runnable
116  {
117  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) entering running mode",__LINE__, __FILE__));
118  // call runnable prerun method before running:
119  runnable->PreRun((void *) 0); // we are runnable's friend, can call protected method...
120  while(go4th->IsRunning())
121  {
122  TThread::CancelPoint();
123  runnable->Run((void *) 0); // we are runnable's friend, can call protected method...
124  }
125  // call runnable postrun method before stopping
126  runnable->PostRun((void *) 0); // we are runnable's friend, can call protected method...
127 
128  }
129  else
130  // aborting mode after condition release: loop cancel point
131  {
132  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) entering Cancel loop",__LINE__, __FILE__));
133  TGo4Log::Debug(" Go4Thread ``%s'' entering Cancel loop\n ", go4th->GetName());
134  while(!(go4th->IsCreated()))
135  {
136  {
137  #ifdef _MSC_VER
138  return; // cancel point does not work on windows; escape to root thread framework...
139  #else
140  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) in Cancel loop",__LINE__, __FILE__));
141  Sleep(500);
142  TThread::CancelPoint();
143  #endif
144  }
145  }
146  }
147  } // while(1)
148  }// try
149  catch(TGo4Exception &ex)
150  {
151  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) Go4Exception Catch",__LINE__, __FILE__));
152  runnable->ThreadCatch(ex);
153  TThread::CancelPoint();
154  }
155 
156  catch(...)
157  {
158  GO4TRACE((1,"TGo4Thread::Threadfunc(void *) Unexpected Catch",__LINE__, __FILE__));
159  //runnable->UnexpectedCatch(); // do not handle alien exceptions!
160  TThread::CancelPoint();
161  throw; // otherwise, we have trouble with newer pthread
162  // implementations that use one pid for all threads, e.g. Fedora2
163  }
164 
165  } // for(;;) loop keeps thread alive
166 }
167 
169 {
170  GO4TRACE((14,"TGo4Thread::Create()",__LINE__, __FILE__));
171  // thread instance already there...
172  if(fbIsCreated)
173  return kFALSE;
174 
175  fxThread= new TThread(GetName(),
176  (void(*) (void *)) &Threadfunc ,
177  (void *) this);
178  fxThread->Run();
179  fbIsCreated = kTRUE;
180  return kTRUE;
181 }
182 
184 {
185  GO4TRACE((14,"TGo4Thread::Cancel()",__LINE__, __FILE__));
186 
187  if(fbIsCreated) {
188  // thread existing, then cancel
189  TGo4Log::Debug(" Go4Thread ``%s'' -- Canceling TThread %ld (PID:%d) ",
190  GetName(), fiThreadSelfID, fiThreadPID);
191  if(fxThread) {
192  GO4TRACE((13,"TGo4Thread::Cancel() -- canceling existing TThread",__LINE__, __FILE__));
193  fbIsCreated = kFALSE;
194  fbIsRunning = kTRUE; // these settings let Threadfunc enter Cancel loop
195  fxCondition->Signal(); // unlock condition mutex before deleting it
196  Sleep(500); // waitstate for Threadfunc to enter cancel loop after condition
197 
198  // JAM2018 bugfix for crashes with ROOT 6 concerning Thread CleanUpPop
199  TThread::Delete(fxThread);
200 
201  fxThread = nullptr;
202  fiThreadPID = 0;
203  fiThreadSelfID = 0;
204  } else {
205  GO4TRACE((13,"TGo4Thread::Cancel() -- Error: TThread pointer is zero!",__LINE__, __FILE__));
206  TGo4Log::Debug(" Go4Thread ``%s'' Cancel -- Internal inconsistency error! ",GetName());
207  throw TGo4RuntimeException();
208  }
209  return kTRUE;
210  }
211  // no such thread...
212  return kFALSE;
213 }
214 
216 {
217  GO4TRACE((14,"TGo4Thread::ReCreate()",__LINE__, __FILE__));
218 
219  TThread* oldthread;
220  if(fbIsCreated)
221  // thread existing, then recreate possible
222 
223  {
224  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
225  TGo4Log::Debug(" Recreating Go4Thread ``%s'' -- old TThread %ld (PID:%d) ",
226  GetName(), fiThreadSelfID, fiThreadPID);
227  if(fxThread)
228  {
229  GO4TRACE((13,"TGo4Thread::ReCreate() -- recreating existing TThread",__LINE__, __FILE__));
230  Stop();// halt runnable
231  oldthread=fxThread; // remember old TThread
232  // first start new TThread of same Threadfunc and runnable:
233  fxThread= new TThread(GetName(),
234  (void(*) (void *)) &Threadfunc ,
235  (void *) this);
236 
237  // then kill the old TThread, so Threadfunc may ReCreate() itself
238  fbIsCreated=kFALSE;
239  if(fbIsWaiting)
240  {
241  fxCondition->Signal(); // unlock condition mutex before deleting it
242  // this will not start the runnable, fbIsRunning still false
243  //fbIsWaiting=kFALSE; // keep flag consistent with Threadfunc state..
244  }
245  TThread::Delete(oldthread);
246  //delete oldthread;
247  fbIsCreated=kTRUE;
248  fxThread->Run(); // does this work if thread recreates itself?
249  Start(); // start runnable in new TThread
250 
251  }
252  else
253  {
254  GO4TRACE((13,"TGo4Thread::ReCreate() -- Error: old TThread pointer is zero!",__LINE__, __FILE__));
255  TGo4Log::Debug(" Go4Thread ``%s'' ReCreate -- Internal inconsistency error! ",GetName());
256  throw TGo4RuntimeException();
257  }
258  return kTRUE;
259  }
260  else //if(fbIsCreated)
261  // no old thread, then create new one
262  {
263  GO4TRACE((13,"TGo4Thread::ReCreate() -- old TThread existing",__LINE__, __FILE__));
264  Create();
265  return kFALSE;
266  }
267 }
268 
270 {
271  GO4TRACE((12,"TGo4Thread::Start()",__LINE__, __FILE__));
272  if (!fbIsCreated) {
273  // check if thread is up
274  // not yet created, then do so
275  GO4TRACE((11,"TGo4Thread::Start() -- creating new TThread",__LINE__, __FILE__));
276  Create();
277  } else {
278  // do nothing, thread already there
279  GO4TRACE((11,"TGo4Thread::Start() -- TThread already existing",__LINE__, __FILE__));
280  }
281  Bool_t old = fbIsRunning;
282  fbIsRunning = kTRUE;
283  fxCondition->Signal(); // wake up waiting threadfunction
284  return old; // old status of workfunc requested by thread list
285 }
286 
288 {
289  GO4TRACE((12,"TGo4Thread::Stop()",__LINE__, __FILE__));
290  Bool_t old = fbIsRunning;
291  fbIsRunning = kFALSE;
292  return old; // old status of workfunc requested by thread list
293 }
294 
295 void TGo4Thread::Sleep (UInt_t millisecs)
296 {
297  GO4TRACE((12,"TGo4Thread::Sleep()",__LINE__, __FILE__));
298  gSystem->Sleep(millisecs);
299  TThread::CancelPoint();
300 }
301 
303 {
304  fiThreadSelfID = TThread::SelfId();
305 }
306 
308 {
309  fiThreadPID = gSystem->GetPid();
310 }
virtual void ThreadCatch(TGo4Exception &ex)
Bool_t Stop()
Definition: TGo4Thread.cxx:287
void SetWaiting(Bool_t mode=kTRUE)
Definition: TGo4Thread.h:107
Bool_t Cancel()
Definition: TGo4Thread.cxx:183
static void Sleep(UInt_t millisecs)
Definition: TGo4Thread.cxx:295
static void Threadfunc(void *arg)
Definition: TGo4Thread.cxx:75
TGo4Thread()=delete
Bool_t IsCreated() const
Definition: TGo4Thread.h:82
Long_t GetSelfID() const
Definition: TGo4Thread.h:75
TThread * fxThread
Definition: TGo4Thread.h:140
static void Debug(const char *text,...) GO4_PRINTF_ARGS
Definition: TGo4Log.cxx:281
TCondition * fxCondition
Definition: TGo4Thread.h:142
virtual Int_t PreRun(void *ptr)
Bool_t IsRunning() const
Definition: TGo4Thread.h:85
void SetThread(TGo4Thread *gthread)
Definition: TGo4Runnable.h:42
virtual Int_t Run(void *ptr)=0
void SetPID()
Definition: TGo4Thread.cxx:307
TCondition * GetCondition() const
Definition: TGo4Thread.h:101
virtual Int_t PostRun(void *ptr)
Long_t fiThreadSelfID
Definition: TGo4Thread.h:126
virtual ~TGo4Thread()
Definition: TGo4Thread.cxx:52
TGo4Runnable * fxRunnable
Definition: TGo4Thread.h:138
Int_t fiThreadPID
Definition: TGo4Thread.h:123
Bool_t fbIsRunning
Definition: TGo4Thread.h:120
Bool_t ReCreate()
Definition: TGo4Thread.cxx:215
Bool_t fbIsInternal
Definition: TGo4Thread.h:114
Bool_t Create()
Definition: TGo4Thread.cxx:168
Bool_t fbIsCreated
Definition: TGo4Thread.h:117
#define GO4TRACE(X)
Definition: TGo4Log.h:25
void SetSelfID()
Definition: TGo4Thread.cxx:302
Bool_t Start()
Definition: TGo4Thread.cxx:269
TGo4Runnable * GetRunnable() const
Definition: TGo4Thread.h:99
Bool_t fbIsWaiting
Definition: TGo4Thread.h:129
Int_t GetPID() const
Definition: TGo4Thread.h:72