// @(#)root/thread:$Name: $:$Id: TThread.cxx,v 1.4 2000/09/13 07:58:21 brun Exp $
// Author: Fons Rademakers 02/07/97
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TThread //
// //
// This class implements threads. A thread is an execution environment //
// much lighter than a process. A single process can have multiple //
// threads. The actual work is done via the TThreadImp class (either //
// TThreadPosix, TThreadSolaris or TThreadNT). //
// //
//////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG
#include "config.h"
#endif
#include "TThread.h"
#include "TThreadImp.h"
#include "TThreadFactory.h"
#include "TCanvas.h"
#include "TError.h"
#include "CallFunc.h"
TThreadImp *TThread::fgThreadImp = 0;
TThread *TThread::fgMain = 0;
TMutex *TThread::fgMainMutex;
char *volatile TThread::fgXAct = 0;
TMutex *TThread::fgXActMutex;
TCondition *TThread::fgXActCondi;
void **volatile TThread::fgXArr = 0;
volatile Int_t TThread::fgXAnb = 0;
volatile Int_t TThread::fgXArt = 0;
ClassImp(TThread)
//______________________________________________________________________________
void TThread::Debu(const char *txt)
{
fprintf(stderr,"TThread::Debu %s %d n",txt,fgMain->fId);
}
//______________________________________________________________________________
Int_t TThread::Exists()
{
// Check existing threads
// return number of running Threads
TThread *l;
if (! fgMain) { //no threads
return 0;}
Int_t num=0;
for(l=fgMain; l ; l = l->fNext) {num++;} //count threads
return num;
}
//______________________________________________________________________________
void TThread::SetPriority(EPriority pri)
{
// Set thread priority.
fPriority = pri;
}
//______________________________________________________________________________
void TThread::SetJoinId(Int_t jid)
{
// Set id of thread to join.
fJoinId = jid;
}
//______________________________________________________________________________
void TThread::SetJoinId(TThread *tj)
{
// Set thread to join.
SetJoinId(tj->fId);
}
//______________________________________________________________________________
TThread *TThread::GetThread(Int_t id)
{
// Static method to find a thread by id.
TThread *myth;
for (myth = fgMain; myth && (myth->fId!= id); myth=myth->fNext){};
return myth;
}
//______________________________________________________________________________
TThread *TThread::GetThread(const Text_t *name)
{
// Static method to find a thread by name.
TThread *myth;
for (myth = fgMain; myth && (strcmp(name,myth->GetName())); myth=myth->fNext){};
return myth;
}
//______________________________________________________________________________
TThread *TThread::Self()
{
// Static method returning pointer to current thred.
return GetThread(SelfId());
}
//______________________________________________________________________________
Int_t TThread::Join(void **ret)
{
// Static method to join thread. (rdm?)
return TThread::Join(0, ret);
}
//
// Constructors for TThread - set up the thread object but don't
// start it running.
//
// construct a Detached thread running a given function.
//______________________________________________________________________________
TThread::TThread(void *(*fn)(void*), void *arg, EPriority pri)
{
// Create a thread. Specify the function or static class method
// to be executed by the thread, and a pointer to the argument structure.
// The user functions should return a void*.
fDetached = kFALSE;
fFcnVoid = 0;
fFcnRetn = fn;
fPriority = pri;
fThreadArg = arg;
Constructor();
fNamed = kFALSE;
}
//______________________________________________________________________________
TThread::TThread(void (*fn)(void*), void *arg, EPriority pri)
{
// Create a thread. Specify the function or class method
// to be executed by the thread, and a pointer to the argument structure.
fDetached = kTRUE;
fFcnRetn = 0;
fFcnVoid = fn;
fPriority = pri;
fThreadArg = arg;
Constructor();
fNamed = kFALSE;
}
////////// begin changes (J.A.):
// additional constructors with own threadname thname
// as useful for invoking thread with name from compiled program:
//______________________________________________________________________________
TThread::TThread(const Text_t *thname, void *(*fn)(void*), void *arg, EPriority pri)
{
// Create thread with a name. For the ..... //till here
SetName(thname); // set TNamed name to thname anyway, will be overwritten
//if G__p2f2funcname-method recognizes true name of fn (call by interpreter)
fDetached = kFALSE;
fFcnVoid = 0;
fFcnRetn = fn;
fPriority = pri;
fThreadArg = arg;
Constructor();
fNamed = kTRUE;
//TThread(fn,arg,pri); // use normal TThread joinable constructor
}
TThread::TThread(const Text_t *thname, void (*fn)(void*), void* arg, EPriority pri){
SetName(thname); // set TNamed name to thname anyway, will be overwritten
//if G__p2f2funcname-method recognizes true name of fn (call by interpreter)
fDetached = kTRUE;
fFcnRetn = 0;
fFcnVoid = fn;
fPriority = pri;
fThreadArg = arg;
Constructor();
fNamed = kTRUE;
//TThread(fn,arg,pri); // use normal TThread detached constructor
}
/////////////// end changes (J.A.)
void TThread::Constructor() {
fState = kNewState;
fId = 0;
if (!fgThreadImp) { // *** Only once ***
fgThreadImp = gThreadFactory->CreateThreadImp();
fgMainMutex = new TMutex;
fgXActMutex = new TMutex;
new TThreadTimer;
fgXActCondi = new TCondition;
gThreadTsd = &(TThread::Tsd);
gThreadXAR = &(TThread::XARequest);
}
PutComm("Constructor: MainMutex Locking");
Lock();
PutComm("Constructor: MainMutex Locked");
fTsd[0] = gPad;
if (fgMain) fgMain->fPrev = this;
fNext = fgMain; fPrev=0; fgMain = this;
UnLock();
PutComm();
// thread is set up in initialisation routine or start().
}
TThread::~TThread()
{
char cbuf[100];
if (gDebug) {
sprintf(cbuf,"*** Thread %s.%d is DELETED ***",GetName(),fId);
TThread::Printf("n %sn\n",cbuf);
}
// Disconnect thread instance
PutComm("Destructor: MainMutex Locking");
Lock();
PutComm("Destructor: MainMutex Locked");
if (fPrev) fPrev->fNext = fNext;
if (fNext) fNext->fPrev = fPrev;
if (fgMain == this) fgMain = fNext;
UnLock();
PutComm();
if (fHolder) *(fHolder) = 0;
}
Int_t TThread::Delete(TThread* &th)
{
char cbuf[100];
if (! th) return 0;
th->fHolder = &(th);
if (th->fState == kRunningState) {// Cancel if running
th->fState = kDeletingState;
if (gDebug) {
sprintf(cbuf,"*** Thread %s.%d Deleting ***",th->GetName(),th->fId);
TThread::Printf("n %sn\n",cbuf);
}
th->Kill(); return -1;}
th->CleanUp();
return 0;
}
// Implementation dependent part of member function
Int_t TThread::Join(Int_t jid, void **ret)
{
Int_t jd = jid;
if (! jd) {// jd is not known
TThread *myth = TThread::Self();
if (! myth) return -1;
jd = myth->fJoinId;
if (! jd ) return -1;
}
return fgThreadImp->Join(jd,ret);
}
Int_t TThread::SelfId()
{Int_t id = fgThreadImp->SelfId();
if (! id) id = -1; // in some implementations 0 is main thread
return id;
}
Int_t TThread::Run(void *arg)
{
char *fname = 0;
if (arg) fThreadArg = arg;
PutComm("Run: MainMutex locking");
Lock();
PutComm("Run: MainMutex locked");
if (fFcnVoid) fname=G__p2f2funcname((void*)fFcnVoid);
if (fFcnRetn) fname=G__p2f2funcname((void*)fFcnRetn);
if(!fNamed)
if (fname) SetName(fname);
int iret = fgThreadImp->Run (this);
fState = (iret) ? kInvalidState : kRunningState;
if (gDebug) {
fprintf(stderr,"nThread %s ID=%d requestedn\n",GetName(),fId);
}
UnLock();
PutComm();
return iret;
}
Int_t TThread::Kill()
{
if (fState != kRunningState && fState != kDeletingState) {
if (gDebug) {
fprintf(stderr,"TThread::Kill. thread %d is not runningn",fId);
}
return 13;
} else {
if (fState == kRunningState ) fState = kCancelingState;
return fgThreadImp->Kill(this);
}
}
Int_t TThread::Kill(Int_t id)
{
TThread *th = GetThread(id);
if (th) {return fgThreadImp->Kill(th);
} else {
if (gDebug) {
fprintf(stderr,"TThread::Kill thread %d not found ***n",id);
}
return 13;
}
}
Int_t TThread::Kill(const Text_t *name)
{
TThread *th = GetThread(name);
if (th) {return fgThreadImp->Kill(th);
} else {
if (gDebug) {
fprintf(stderr,"TThread::Kill thread %s not found ***n",name);
}
return 13;
}
}
Int_t TThread::SetCancelOff(){return fgThreadImp-> SetCancelOff();}
Int_t TThread::SetCancelOn() {return fgThreadImp->SetCancelOn();}
Int_t TThread::SetCancelAsynchronous(){return fgThreadImp->SetCancelAsynchronous();}
Int_t TThread::SetCancelDeferred() {return fgThreadImp->SetCancelDeferred();}
Int_t TThread::CancelPoint(){return fgThreadImp->CancelPoint();}
Int_t TThread::CleanUpPush(void *free,void *arg)
{
return fgThreadImp->CleanUpPush(&(Self()->fClean),free,arg);
}
Int_t TThread::CleanUpPop(Int_t exe)
{
return fgThreadImp->CleanUpPop(&(Self()->fClean),exe);
}
Int_t TThread::CleanUp()
{
TThread *th = Self();
if (! th) return 13;
fgThreadImp->CleanUp(&(Self()->fClean));
th->fgMainMutex->CleanUp();
th->fgXActMutex->CleanUp();
if(th->fHolder) { // It was kill from delete
delete th;
};
return 0;
}
void TThread::AfterCancel(TThread *th)
{
th->fState = kCanceledState;
if (gDebug) {
char cbuf[100];
sprintf(cbuf,"*** Thread %s.%d is KILLED ***",th->GetName(),th->fId);
TThread::Printf("n %sn\n",cbuf);
}
}
Int_t TThread::Exit(void *ret)
{
return fgThreadImp->Exit(ret);
}
Int_t TThread::Sleep(ULong_t secs, ULong_t nanos )
{
return fgThreadImp->Sleep( secs, nanos);
}
Int_t TThread::GetTime(ULong_t *absSec, ULong_t *absNanoSec)
{
return fgThreadImp->GetTime( absSec, absNanoSec);
}
Int_t TThread::Lock() {return fgMainMutex->Lock(); } // lock main mutex
Int_t TThread::TryLock(){return fgMainMutex->TryLock();} // lock main mutex
Int_t TThread::UnLock() {return fgMainMutex->UnLock();} // unlock main mutex
unsigned long TThread::Call(void *p2f,void *arg) {
char *fname;
void *iPointer2Function;
G__CallFunc fFunc;
int iPointerType = G__UNKNOWNFUNC;
// reconstruct function name
fname=G__p2f2funcname(p2f);
iPointer2Function=p2f;
if(fname) {
G__ClassInfo globalscope;
G__MethodInfo method;
long dummy;
// resolve function overloading
method=globalscope.GetMethod(fname,"void*",&dummy);
if(method.IsValid()) {
// get pointer to function again after overloading resolution
iPointer2Function=method.PointerToFunc();
// check what kind of pointer is it
iPointerType = G__isinterpretedp2f(iPointer2Function);
switch(iPointerType) {
case G__COMPILEDINTERFACEMETHOD: // using interface method
fFunc.SetFunc((G__InterfaceMethod)iPointer2Function);
break;
case G__BYTECODEFUNC: // bytecode version of interpreted func
fFunc.SetBytecode((struct G__bytecodefunc*)iPointer2Function);
}
}
else {
::Error("TThread:Call", "no overloading parameter matches");
}
}
// check what kind of pointer is it
switch(iPointerType) {
case G__INTERPRETEDFUNC: // reconstruct function call as string
char temp[20],para[200];
strcpy(para,(char*)iPointer2Function);
strcat(para,"(");
sprintf(temp,"(void*)%#lx,",(unsigned long)arg);
strcat(para,temp); strcat(para,")");
return G__int(G__calc(para));
case G__COMPILEDINTERFACEMETHOD: // using interface method
case G__BYTECODEFUNC: // bytecode version of interpreted func
fFunc.SetArg((long)arg);
return fFunc.ExecInt((void*)0);
case G__COMPILEDTRUEFUNC: // using true pointer to function
case G__UNKNOWNFUNC: // this case will never happen
return (*(int (*)(void*))iPointer2Function)(arg);
}
::Error("TThread::Call", "*** Something very WRONG ***");
return 0xffffffff;
}
void *TThread::Fun(void *ptr) {
TThread *th;
void *ret,*arg;
char cbuf[100];
TThreadCleaner dummy;
th = (TThread *)ptr;
// Default cancel state is OFF
// Default cancel type is DEFERRED
// User can change it by call SetCancelON & SetCancelAsynchronous()
SetCancelOff();
SetCancelDeferred();
CleanUpPush((void *)&AfterCancel,th); // Enable standard cancelling function
th = (TThread *)ptr;
th->fId = SelfId(); th->SetUniqueID(th->fId);
sprintf(cbuf,"Thread %s.%d is running",th->GetName(),th->fId);
TThread::Printf("n %sn\n",cbuf);
arg = th->fThreadArg;
th->fState = kRunningState;
if (th->fDetached) { //Detached, non joinable thread
TThread::Call((void*)th->fFcnVoid,arg);
ret = 0;
th->fState = kFinishedState;
} else { //UnDetached, joinable thread
ret = (void*)TThread::Call((void*)th->fFcnRetn,arg);
th->fState = kTerminatedState;
}
//CleanUpPop(0);// Disable standard cancelling function
CleanUpPop(1);// Disable standard cancelling function
sprintf(cbuf,"Thread %s.%d finished",th->GetName(),th->fId);
TThread::Printf("n %sn\n",cbuf);
TThread::Exit(ret);
return ret;
}
void TThread::Ps() { // List existing threads
TThread *l;
int i;
if (! fgMain) { //no threads
printf("*** No threads, ***n"); return;}
Lock();
int num=0; for(l=fgMain; l ; l = l->fNext) {num++;};
char cbuf[100];
printf(" Thread Staten");
for (l = fgMain; l; l = l->fNext) { // loop over threads
memset(cbuf,' ',100);
sprintf(cbuf, "%3d %s.%d",num--,l->GetName(),l->fId);
i = strlen(cbuf); if (i<20) cbuf[i]=' '; cbuf[20]=0;
printf("%20s",cbuf);
switch (l->fState) {// print states
case kNewState: printf("Idle "); break;
case kRunningState: printf("Running "); break;
case kTerminatedState: printf("Terminated "); break;
case kFinishedState: printf("Finished "); break;
case kCancelingState: printf("Canceling "); break;
case kCanceledState: printf("Canceled "); break;
case kDeletingState: printf("Deleting "); break;
default: printf("Invalid ");
};
if (l->fComm[0]) printf(" // %sn",l->fComm);
printf("n");
}// end of loop
UnLock();
}
void **TThread::Tsd(void *dflt,Int_t k) {
TThread *th = TThread::Self();
if (!th) {//Main thread
return (void**)dflt;
} else {
return &(th->fTsd[k]);
}
}
void TThread::Printf(const char *txt) {
Printf(txt,0);
}
void TThread::Printf(const char *txt,Int_t in) {
void *arr[3];
arr[1] = (void*)txt; arr[2] = ∈
if (XARequest("PRTF", 3, arr, 0)) return;
fprintf(stderr,txt,in);
}
Int_t TThread::XARequest(const char *xact, Int_t nb, void **ar, Int_t *iret) {
TThread *th;
if ((th=Self())) { // we are in the thread
th->PutComm("XARequest: XActMutex Locking");
fgXActMutex ->Lock();
th->PutComm("XARequest: XActMutex Locked");
fgXAnb = nb;
fgXArr = ar;
fgXArt = 0;
fgXAct = (char*)xact;
// while(fgXAct) {gSystem->Sleep(10);};
// th->PutComm("XARequest: Condition Wait");
th->PutComm(fgXAct);
// THis nasty tric for Linux only
// fgXActCondi->Wait();
while (fgXAct) {fgXActCondi->TimedWait(1);}
th->PutComm();
if (iret) *iret = fgXArt;
fgXActMutex ->UnLock();
th->PutComm();
return 1997;
} else { //we are in the main thread
return 0;
}
}
void TThread::XAction()
{
char const acts[] = "PRTF CUPD CANV CDEL";
enum {kPRTF=0,kCUPD=5,kCANV=10,kCDEL=15};
int iact = strstr(acts,fgXAct) - acts;
switch(iact) {
case kPRTF:
fprintf(stderr,(char*)fgXArr[1],*((Int_t*)(fgXArr[2])));
break;
case kCUPD:
((TCanvas *)fgXArr[1])->Update();
break;
case kCANV:
switch(fgXAnb) { // Over TCanvas constructors
case 2:
((TCanvas*)fgXArr[1])->Constructor();
break;
case 6:
((TCanvas*)fgXArr[1])->Constructor(
(Text_t*)fgXArr[2],
(Text_t*)fgXArr[3],
*((Int_t*)(fgXArr[4])),
*((Int_t*)(fgXArr[5])));
break;
case 8:
((TCanvas*)fgXArr[1])->Constructor(
(Text_t*)fgXArr[2],
(Text_t*)fgXArr[3],
*((Int_t*)(fgXArr[4])),
*((Int_t*)(fgXArr[5])),
*((Int_t*)(fgXArr[6])),
*((Int_t*)(fgXArr[7])));
break;
}
gSystem->Sleep(10000);
break;
case kCDEL:
((TCanvas*)fgXArr[1])->Destructor();
break;
default: fprintf(stderr,"TThread::XARequest. Wrong casen");
}
fgXAct = 0;
fgXActCondi->Signal();
}
Int_t TThread::MakeFun(char *funname)
{ int iret;
char cbuf[100];
#ifndef ROOTDATADIR
sprintf(cbuf,"make -f $ROOTSYS/thread/MakeFun.mk fun=%s",funname);
#else
sprintf(cbuf,"make -f " ROOTDATADIR "/thread/MakeFun.mk fun=%s",funname);
#endif
if ((iret = gSystem->Exec(cbuf))) return iret;
sprintf(cbuf,"%s.so",funname);
return gSystem->Load(cbuf);
}
//////////////////////////////////////////////////////////////////////////
// //
// TThreadTimer //
// //
//////////////////////////////////////////////////////////////////////////
//______________________________________________________________________________
TThreadTimer::TThreadTimer( Long_t ms) : TTimer( ms, kTRUE )
{
gSystem->AddTimer(this);
}
Bool_t TThreadTimer::Notify()
{
if( TThread::fgXAct ) { TThread::XAction();}
Reset();
return( kFALSE );
}
//////////////////////////////////////////////////////////////////////////
// //
// TThreadCleaner //
// //
//////////////////////////////////////////////////////////////////////////
TThreadCleaner::~TThreadCleaner()
{
TThread::CleanUp(); // Call user clean up routines
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.