ROOT logo
// @(#)root/thread:$Id$
// 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    //
// TPosixThread or TWin32Thread).                                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "RConfigure.h"

#include "TThread.h"
#include "TThreadImp.h"
#include "TThreadFactory.h"
#include "TROOT.h"
#include "TApplication.h"
#include "TVirtualPad.h"
#include "TMethodCall.h"
#include "TTimeStamp.h"
#include "TInterpreter.h"
#include "TError.h"
#include "Varargs.h"
#include "ThreadLocalStorage.h"

TThreadImp     *TThread::fgThreadImp = 0;
Long_t          TThread::fgMainId = 0;
TThread        *TThread::fgMain = 0;
TMutex         *TThread::fgMainMutex;
char  *volatile TThread::fgXAct = 0;
TMutex         *TThread::fgXActMutex = 0;
TCondition     *TThread::fgXActCondi = 0;
void **volatile TThread::fgXArr = 0;
volatile Int_t  TThread::fgXAnb = 0;
volatile Int_t  TThread::fgXArt = 0;

static void CINT_alloc_lock()   { gGlobalMutex->Lock(); }
static void CINT_alloc_unlock() { gGlobalMutex->UnLock(); }

static TMutex  *gMainInternalMutex = 0;

static void ThreadInternalLock() { if (gMainInternalMutex) gMainInternalMutex->Lock(); }
static void ThreadInternalUnLock() { if (gMainInternalMutex) gMainInternalMutex->UnLock(); }

static Bool_t fgIsTearDown(kFALSE);

//------------------------------------------------------------------------------

// Set gGlobalMutex to 0 when Thread library gets unloaded
class TThreadTearDownGuard {
public:
   TThreadTearDownGuard() { fgIsTearDown = kFALSE; }
   ~TThreadTearDownGuard() {
      // Note: we could insert here a wait for all thread to be finished.
      // this is questionable though as we need to balance between fixing a
      // user error (the thread was let lose and the caller did not explicit wait)
      // and the risk that we can not terminate a failing process.

      fgIsTearDown = kTRUE;
      TVirtualMutex *m = gGlobalMutex;
      gGlobalMutex = 0;
      delete m;
      TThreadImp *imp = TThread::fgThreadImp;
      TThread::fgThreadImp = 0;
      delete imp;
   }
};
static TThreadTearDownGuard gTearDownGuard;

//------------------------------------------------------------------------------

class TJoinHelper {
private:
   TThread    *fT;
   TThread    *fH;
   void      **fRet;
   Long_t      fRc;
   TMutex     *fM;
   TCondition *fC;
   Bool_t      fJoined;

   static void* JoinFunc(void *p);

public:
   TJoinHelper(TThread *th, void **ret);
   ~TJoinHelper();

   Int_t Join();
};

//______________________________________________________________________________
TJoinHelper::TJoinHelper(TThread *th, void **ret)
   : fT(th), fRet(ret), fRc(0), fM(new TMutex), fC(new TCondition(fM)), fJoined(kFALSE)
{
   // Constructor of Thread helper class.

   fH = new TThread("JoinHelper", JoinFunc, this);
}

//______________________________________________________________________________
TJoinHelper::~TJoinHelper()
{
   // Destructor.

   delete fC;
   delete fM;
   delete fH;
}

//______________________________________________________________________________
void* TJoinHelper::JoinFunc(void *p)
{
   // Static method which runs in a separate thread to handle thread
   // joins without blocking the main thread.
   // Return a value (zero) so that it makes a joinable thread.

   TJoinHelper *jp = (TJoinHelper*)p;

   jp->fRc = jp->fT->Join(jp->fRet);

   jp->fM->Lock();
   jp->fJoined = kTRUE;
   jp->fC->Signal();
   jp->fM->UnLock();

   TThread::Exit(0);

   return 0;
}

//______________________________________________________________________________
Int_t TJoinHelper::Join()
{
   // Thread join function.

   fM->Lock();
   fH->Run();

   while (kTRUE) {
      // TimedWaitRelative will release the mutex (i.e. equivalent to fM->Unlock),
      // then block on the condition variable.  Upon return it will lock the mutex.
      int r = fC->TimedWaitRelative(100);  // 100 ms

      // From the man page from pthread_ond_timedwait:

      // When using condition variables there is always a Boolean predicate
      // involving shared variables associated with each condition wait that
      // is true if the thread should proceed. Spurious wakeups from the
      // pthread_cond_timedwait() or pthread_cond_wait() functions may occur.
      // Since the return from pthread_cond_timedwait() or pthread_cond_wait()
      // does not imply anything about the value of this predicate, the
      // predicate should be re-evaluated upon such return.

      if (r == 0 || r == 1) {
         // If we received the signal or timed out, let's check the value
         if (fJoined) break;
      } else {
         // If any other error occured, there is no point in trying again
         break;
      }

      gSystem->ProcessEvents();
   }

   fM->UnLock();

   // And wait for the help to finish to avoid the risk that it is still
   // running when the main tread is finished (and the thread library unloaded!)
   TThread::fgThreadImp->Join(fH, 0);

   return fRc;
}


//------------------------------------------------------------------------------

ClassImp(TThread)


//______________________________________________________________________________
TThread::TThread(VoidRtnFunc_t fn, void *arg, EPriority pri)
   : TNamed("<anon>", "")
{
   // 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 function should return a void*. To start the thread call Run().

   fDetached  = kFALSE;
   fFcnVoid   = 0;
   fFcnRetn   = fn;
   fPriority  = pri;
   fThreadArg = arg;
   Constructor();
   fNamed     = kFALSE;
}

//______________________________________________________________________________
TThread::TThread(VoidFunc_t fn, void *arg, EPriority pri)
   : TNamed("<anon>", "")
{
   // Create a detached thread. Specify the function or static class method
   // to be executed by the thread and a pointer to the argument structure.
   // To start the thread call Run().

   fDetached  = kTRUE;
   fFcnRetn   = 0;
   fFcnVoid   = fn;
   fPriority  = pri;
   fThreadArg = arg;
   Constructor();
   fNamed     = kFALSE;
}

//______________________________________________________________________________
TThread::TThread(const char *thname, VoidRtnFunc_t fn, void *arg,
                 EPriority pri) : TNamed(thname, "")
{
   // Create thread with a name. Specify the function or static class method
   // to be executed by the thread and a pointer to the argument structure.
   // The user function should return a void*. To start the thread call Run().

   fDetached  = kFALSE;
   fFcnVoid   = 0;
   fFcnRetn   = fn;
   fPriority  = pri;
   fThreadArg = arg;
   Constructor();
   fNamed     = kTRUE;
}

//______________________________________________________________________________
TThread::TThread(const char *thname, VoidFunc_t fn, void *arg,
                 EPriority pri) : TNamed(thname, "")
{
   // Create a detached thread with a name. Specify the function or static
   // class method to be executed by the thread and a pointer to the argument
   // structure. To start the thread call Run().

   fDetached  = kTRUE;
   fFcnRetn   = 0;
   fFcnVoid   = fn;
   fPriority  = pri;
   fThreadArg = arg;
   Constructor();
   fNamed     = kTRUE;
}

//______________________________________________________________________________
TThread::TThread(Long_t id)
{
   // Create a TThread for a already running thread.

   fDetached  = kTRUE;
   fFcnRetn   = 0;
   fFcnVoid   = 0;
   fPriority  = kNormalPriority;
   fThreadArg = 0;
   Constructor();

   // Changing the id must be protected as it will be look at by multiple
   // threads (see TThread::GetThread)
   ThreadInternalLock();
   fNamed     = kFALSE;
   fId = (id ? id : SelfId());
   fState = kRunningState;
   ThreadInternalUnLock();

   if (gDebug)
      Info("TThread::TThread", "TThread attached to running thread");
}

//______________________________________________________________________________
void TThread::Initialize()
{
   // Initialize the Thread package. This initializes the TThread and ROOT
   // global mutexes to make parts of ROOT thread safe/aware. This call is
   // implicit in case a TThread is created.

   Init();
}

//______________________________________________________________________________
Bool_t TThread::IsInitialized()
{
   // Return true, if the TThread objects have been initialize. If false,
   // the process is (from ROOT's point of view) single threaded.

   if (fgThreadImp)
      return kTRUE;
   return kFALSE;
}

//______________________________________________________________________________
void TThread::Init()
{
   // Initialize global state and variables once.

   if (fgThreadImp || fgIsTearDown) return;

   fgThreadImp = gThreadFactory->CreateThreadImp();
   gMainInternalMutex = new TMutex(kTRUE);

   fgMainId    = fgThreadImp->SelfId();
   fgMainMutex = new TMutex(kTRUE);
   gThreadTsd  = TThread::Tsd;
   gThreadXAR  = TThread::XARequest;


   // Create the single global mutex
   gGlobalMutex = new TMutex(kTRUE);
   gCint->SetAlloclockfunc(CINT_alloc_lock);
   gCint->SetAllocunlockfunc(CINT_alloc_unlock);

   //To avoid deadlocks, gCintMutex and gROOTMutex need
   // to point at the same instance
   {
     R__LOCKGUARD(gGlobalMutex);
     if (!gCINTMutex) {
       gCINTMutex = gGlobalMutex->Factory(kTRUE);
     }
     gROOTMutex = gCINTMutex;
   }
}

//______________________________________________________________________________
void TThread::Constructor()
{
   // Common thread constructor.

   fHolder = 0;
   fClean  = 0;
   fState  = kNewState;

   fId = -1;
   fHandle= 0;
   if (!fgThreadImp) Init();

   SetComment("Constructor: MainInternalMutex Locking");
   ThreadInternalLock();
   SetComment("Constructor: MainInternalMutex Locked");
   memset(fTsd, 0, ROOT::kMaxThreadSlot*sizeof(void*));
   // In order for the thread 'gDirectory' value to be properly
   // initialized we need to set it now (otherwise it default
   // to zero which is 'unexpected')
   // We initialize it to gROOT rather than gDirectory, since
   // TFile are currently expected to not be shared by two threads.
   fTsd[ROOT::kDirectoryThreadSlot] = gROOT;

   if (fgMain) fgMain->fPrev = this;
   fNext = fgMain; fPrev = 0; fgMain = this;

   ThreadInternalUnLock();
   SetComment();

   // thread is set up in initialisation routine or Run().
}

//______________________________________________________________________________
TThread::~TThread()
{
   // Cleanup the thread.

   if (gDebug)
      Info("TThread::~TThread", "thread deleted");

   // Disconnect thread instance

   SetComment("Destructor: MainInternalMutex Locking");
   ThreadInternalLock();
   SetComment("Destructor: MainInternalMutex Locked");

   if (fPrev) fPrev->fNext = fNext;
   if (fNext) fNext->fPrev = fPrev;
   if (fgMain == this) fgMain = fNext;

   ThreadInternalUnLock();
   SetComment();
   if (fHolder) *fHolder = 0;
}

//______________________________________________________________________________
Int_t TThread::Delete(TThread *&th)
{
   // Static method to delete the specified thread.
   // Returns -1 in case the thread was running and has been killed. Returns
   // 0 in case the thread has been Delete and Cleaned up. The th pointer is
   // not valid anymore in that case.

   if (!th) return 0;
   th->fHolder = &th;

   if (th->fState == kRunningState) {     // Cancel if running
      th->fState = kDeletingState;

      if (gDebug)
         th->Info("TThread::Delete", "deleting thread");

      th->Kill();
      return -1;
   }

   CleanUp();
   return 0;
}

//______________________________________________________________________________
Int_t TThread::Exists()
{
   // Static method to check if threads exist.
   // Returns the number of running threads.

   ThreadInternalLock();

   Int_t num = 0;
   for (TThread *l = fgMain; l; l = l->fNext)
      num++; //count threads

   ThreadInternalUnLock();

   return num;
}

//______________________________________________________________________________
void TThread::SetPriority(EPriority pri)
{
   // Set thread priority.

   fPriority = pri;
}

//______________________________________________________________________________
TThread *TThread::GetThread(Long_t id)
{
   // Static method to find a thread by id.

   TThread *myTh;

   ThreadInternalLock();

   for (myTh = fgMain; myTh && (myTh->fId != id); myTh = myTh->fNext) { }

   ThreadInternalUnLock();

   return myTh;
}

//______________________________________________________________________________
TThread *TThread::GetThread(const char *name)
{
   // Static method to find a thread by name.

   TThread *myTh;

   ThreadInternalLock();

   for (myTh = fgMain; myTh && (strcmp(name, myTh->GetName())); myTh = myTh->fNext) { }

   ThreadInternalUnLock();

   return myTh;
}

//______________________________________________________________________________
TThread *TThread::Self()
{
   // Static method returning pointer to current thread.

   TTHREAD_TLS(TThread*) self = 0;

   if (!self || fgIsTearDown) {
      if (fgIsTearDown) self = 0;
      self = GetThread(SelfId());
   }
   return self;
}


//______________________________________________________________________________
Long_t TThread::Join(void **ret)
{
   // Join this thread.

   if (fId == -1) {
      Error("Join", "thread not running");
      return -1;
   }

   if (fDetached) {
      Error("Join", "cannot join detached thread");
      return -1;
   }

   if (SelfId() != fgMainId)
      return fgThreadImp->Join(this, ret);

   // do not block the main thread, use helper thread
   TJoinHelper helper(this, ret);

   return helper.Join();
}

//______________________________________________________________________________
Long_t TThread::Join(Long_t jid, void **ret)
{
   // Static method to join a thread by id.

   TThread *myTh = GetThread(jid);

   if (!myTh) {
      ::Error("TThread::Join", "cannot find thread 0x%lx", jid);
      return -1L;
   }

   return myTh->Join(ret);
}

//______________________________________________________________________________
Long_t TThread::SelfId()
{
   // Static method returning the id for the current thread.

   if (fgIsTearDown) return -1;
   if (!fgThreadImp) Init();

   return fgThreadImp->SelfId();
}

//______________________________________________________________________________
Int_t TThread::Run(void *arg)
{
   // Start the thread. This starts the static method TThread::Function()
   // which calls the user function specified in the TThread ctor with
   // the arg argument. Returns 0 on success, otherwise an error number will
   // be returned.

   if (arg) fThreadArg = arg;

   SetComment("Run: MainInternalMutex locking");
   ThreadInternalLock();
   SetComment("Run: MainMutex locked");

   int iret = fgThreadImp->Run(this);

   fState = iret ? kInvalidState : kRunningState;

   if (gDebug)
      Info("TThread::Run", "thread run requested");

   ThreadInternalUnLock();
   SetComment();
   return iret;
}

//______________________________________________________________________________
Int_t TThread::Kill()
{
   // Kill this thread. Returns 0 on success, otherwise an error number will
   // be returned.

   if (fState != kRunningState && fState != kDeletingState) {
      if (gDebug)
         Warning("TThread::Kill", "thread is not running");
      return 13;
   } else {
      if (fState == kRunningState ) fState = kCancelingState;
      return fgThreadImp->Kill(this);
   }
}

//______________________________________________________________________________
Int_t TThread::Kill(Long_t id)
{
   // Static method to kill the thread by id. Returns 0 on success, otherwise
   // an error number will be returned.

   TThread *th = GetThread(id);
   if (th) {
      return fgThreadImp->Kill(th);
   } else  {
      if (gDebug)
         ::Warning("TThread::Kill(Long_t)", "thread 0x%lx not found", id);
      return 13;
   }
}

//______________________________________________________________________________
Int_t TThread::Kill(const char *name)
{
   // Static method to kill thread by name. Returns 0 on success, otherwise
   // an error number will be returned.

   TThread *th = GetThread(name);
   if (th) {
      return fgThreadImp->Kill(th);
   } else  {
      if (gDebug)
         ::Warning("TThread::Kill(const char*)", "thread %s not found", name);
      return 13;
   }
}

//______________________________________________________________________________
Int_t TThread::SetCancelOff()
{
   // Static method to turn off thread cancellation. Returns 0 on success,
   // otherwise an error number will be returned.

   return fgThreadImp ? fgThreadImp->SetCancelOff() : -1;
}

//______________________________________________________________________________
Int_t TThread::SetCancelOn()
{
   // Static method to turn on thread cancellation. Returns 0 on success,
   // otherwise an error number will be returned.

   return fgThreadImp ? fgThreadImp->SetCancelOn() : -1;
}

//______________________________________________________________________________
Int_t TThread::SetCancelAsynchronous()
{
   // Static method to set the cancellation response type of the calling thread
   // to asynchronous, i.e. cancel as soon as the cancellation request
   // is received.

   return fgThreadImp ? fgThreadImp->SetCancelAsynchronous() : -1;
}

//______________________________________________________________________________
Int_t TThread::SetCancelDeferred()
{
   // Static method to set the cancellation response type of the calling thread
   // to deferred, i.e. cancel only at next cancellation point.
   // Returns 0 on success, otherwise an error number will be returned.

   return fgThreadImp ? fgThreadImp->SetCancelDeferred() : -1;
}

//______________________________________________________________________________
Int_t TThread::CancelPoint()
{
   // Static method to set a cancellation point. Returns 0 on success, otherwise
   // an error number will be returned.

   return fgThreadImp ? fgThreadImp->CancelPoint() : -1;
}

//______________________________________________________________________________
Int_t TThread::CleanUpPush(void *free, void *arg)
{
   // Static method which pushes thread cleanup method on stack.
   // Returns 0 in case of success and -1 in case of error.

   TThread *th = Self();
   if (th)
      return fgThreadImp->CleanUpPush(&(th->fClean), free, arg);
   return -1;
}

//______________________________________________________________________________
Int_t TThread::CleanUpPop(Int_t exe)
{
   // Static method which pops thread cleanup method off stack.
   // Returns 0 in case of success and -1 in case of error.

   TThread *th = Self();
   if (th)
      return fgThreadImp->CleanUpPop(&(th->fClean), exe);
   return -1;
}

//______________________________________________________________________________
Int_t TThread::CleanUp()
{
   // Static method to cleanup the calling thread.

   TThread *th = Self();
   if (!th) return 13;

   fgThreadImp->CleanUp(&(th->fClean));
   fgMainMutex->CleanUp();
   if (fgXActMutex)
      fgXActMutex->CleanUp();

   gMainInternalMutex->CleanUp();

   if (th->fHolder)
      delete th;

   return 0;
}

//______________________________________________________________________________
void TThread::AfterCancel(TThread *th)
{
   // Static method which is called after the thread has been canceled.

   if (th) {
      th->fState = kCanceledState;
      if (gDebug)
         th->Info("TThread::AfterCancel", "thread is canceled");
   } else
      ::Error("TThread::AfterCancel", "zero thread pointer passed");
}

//______________________________________________________________________________
Int_t TThread::Exit(void *ret)
{
   // Static method which terminates the execution of the calling thread.

   return fgThreadImp ? fgThreadImp->Exit(ret) : -1;
}

//______________________________________________________________________________
Int_t TThread::Sleep(ULong_t secs, ULong_t nanos)
{
   // Static method to sleep the calling thread.

   UInt_t ms = UInt_t(secs * 1000) + UInt_t(nanos / 1000000);
   if (gSystem) gSystem->Sleep(ms);
   return 0;
}

//______________________________________________________________________________
Int_t TThread::GetTime(ULong_t *absSec, ULong_t *absNanoSec)
{
   // Static method to get the current time. Returns
   // the number of seconds.

   TTimeStamp t;
   if (absSec)     *absSec     = t.GetSec();
   if (absNanoSec) *absNanoSec = t.GetNanoSec();
   return t.GetSec();
}

//______________________________________________________________________________
Int_t TThread::Lock()
{
   // Static method to lock the main thread mutex.

   return (fgMainMutex ? fgMainMutex->Lock() : 0);
}

//______________________________________________________________________________
Int_t TThread::TryLock()
{
   // Static method to try to lock the main thread mutex.

   return (fgMainMutex ? fgMainMutex->TryLock() : 0);
}

//______________________________________________________________________________
Int_t TThread::UnLock()
{
   // Static method to unlock the main thread mutex.

   return (fgMainMutex ? fgMainMutex->UnLock() : 0);
}

//______________________________________________________________________________
void *TThread::Function(void *ptr)
{
   // Static method which is called by the system thread function and
   // which in turn calls the actual user function.

   TThread *th;
   void *ret, *arg;

   TThreadCleaner dummy;

   th = (TThread *)ptr;

   // Default cancel state is OFF
   // Default cancel type  is DEFERRED
   // User can change it by call SetCancelOn() and SetCancelAsynchronous()
   SetCancelOff();
   SetCancelDeferred();
   CleanUpPush((void *)&AfterCancel, th);  // Enable standard cancelling function

   if (gDebug)
      th->Info("TThread::Function", "thread is running");

   arg = th->fThreadArg;
   th->fState = kRunningState;

   if (th->fDetached) {
      //Detached, non joinable thread
      (th->fFcnVoid)(arg);
      ret = 0;
      th->fState = kFinishedState;
   } else {
      //UnDetached, joinable thread
      ret = (th->fFcnRetn)(arg);
      th->fState = kTerminatedState;
   }

   CleanUpPop(1);     // Disable standard canceling function

   if (gDebug)
      th->Info("TThread::Function", "thread has finished");

   TThread::Exit(ret);

   return ret;
}

//______________________________________________________________________________
void TThread::Ps()
{
   // Static method listing the existing threads.

   TThread *l;
   int i;

   if (!fgMain) {
      ::Info("TThread::Ps", "no threads have been created");
      return;
   }

   ThreadInternalLock();

   int num = 0;
   for (l = fgMain; l; l = l->fNext)
      num++;

   char cbuf[256];
   printf("     Thread                   State\n");
   for (l = fgMain; l; l = l->fNext) { // loop over threads
      memset(cbuf, ' ', sizeof(cbuf));
      snprintf(cbuf, sizeof(cbuf), "%3d  %s:0x%lx", num--, l->GetName(), l->fId);
      i = strlen(cbuf);
      if (i < 30)
         cbuf[i] = ' ';
      cbuf[30] = 0;
      printf("%30s", 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->fComment[0]) printf("  // %s", l->fComment);
      printf("\n");
   }  // end of loop

   ThreadInternalUnLock();
}

//______________________________________________________________________________
void **TThread::Tsd(void *dflt, Int_t k)
{
   // Static method returning a pointer to thread specific data container
   // of the calling thread.
   // k should be between 0 and kMaxUserThreadSlot for user application.
   // (and between kMaxUserThreadSlot and kMaxThreadSlot for ROOT libraries).
   // See ROOT::EThreadSlotReservation

   TThread *th = TThread::Self();

   if (!th) {   //Main thread
      return (void**)dflt;
   } else {
      return &(th->fTsd[k]);
   }
}

//______________________________________________________________________________
void TThread::Printf(const char *va_(fmt), ...)
{
   // Static method providing a thread safe printf. Appends a newline.

   va_list ap;
   va_start(ap,va_(fmt));

   Int_t buf_size = 2048;
   char *buf;

again:
   buf = new char[buf_size];

   int n = vsnprintf(buf, buf_size, va_(fmt), ap);
   // old vsnprintf's return -1 if string is truncated new ones return
   // total number of characters that would have been written
   if (n == -1 || n >= buf_size) {
      buf_size *= 2;
      delete [] buf;
      goto again;
   }

   va_end(ap);

   void *arr[2];
   arr[1] = (void*) buf;
   if (XARequest("PRTF", 2, arr, 0)) return;

   printf("%s\n", buf);
   fflush(stdout);

   delete [] buf;
}

//______________________________________________________________________________
void TThread::ErrorHandler(int level, const char *location, const char *fmt,
                           va_list ap) const
{
   // Thread specific error handler function.
   // It calls the user set error handler in the main thread.

   Int_t buf_size = 2048;
   char *buf, *bp;

again:
   buf = new char[buf_size];

   int n = vsnprintf(buf, buf_size, fmt, ap);
   // old vsnprintf's return -1 if string is truncated new ones return
   // total number of characters that would have been written
   if (n == -1 || n >= buf_size) {
      buf_size *= 2;
      delete [] buf;
      goto again;
   }
   if (level >= kSysError && level < kFatal) {
      char *buf1 = new char[buf_size + strlen(gSystem->GetError()) + 5];
      sprintf(buf1, "%s (%s)", buf, gSystem->GetError());
      bp = buf1;
      delete [] buf;
   } else
      bp = buf;

   void *arr[4];
   arr[1] = (void*) Long_t(level);
   arr[2] = (void*) location;
   arr[3] = (void*) bp;
   if (XARequest("ERRO", 4, arr, 0)) return;

   if (level != kFatal)
      ::GetErrorHandler()(level, level >= gErrorAbortLevel, location, bp);
   else
      ::GetErrorHandler()(level, kTRUE, location, bp);

   delete [] bp;
}

//______________________________________________________________________________
void TThread::DoError(int level, const char *location, const char *fmt,
                      va_list va) const
{
   // Interface to ErrorHandler. User has to specify the class name as
   // part of the location, just like for the global Info(), Warning() and
   // Error() functions.

   char *loc = 0;

   if (location) {
      loc = new char[strlen(location) + strlen(GetName()) + 32];
      sprintf(loc, "%s %s:0x%lx", location, GetName(), fId);
   } else {
      loc = new char[strlen(GetName()) + 32];
      sprintf(loc, "%s:0x%lx", GetName(), fId);
   }

   ErrorHandler(level, loc, fmt, va);

   delete [] loc;
}

//______________________________________________________________________________
Int_t TThread::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.

   if (!gApplication || !gApplication->IsRunning()) return 0;

   // The first time, create the related static vars
   if (!fgXActMutex && gGlobalMutex) {
      gGlobalMutex->Lock();
      if (!fgXActMutex) {
         fgXActMutex = new TMutex(kTRUE);
         fgXActCondi = new TCondition;
         new TThreadTimer;
      }
      gGlobalMutex->UnLock();
   }

   TThread *th = Self();
   if (th && th->fId != fgMainId) {   // we are in the thread
      th->SetComment("XARequest: XActMutex Locking");
      fgXActMutex->Lock();
      th->SetComment("XARequest: XActMutex Locked");

      TConditionImp *condimp = fgXActCondi->fConditionImp;
      TMutexImp *condmutex = fgXActCondi->GetMutex()->fMutexImp;

      // Lock now, so the XAction signal will wait
      // and never come before the wait
      condmutex->Lock();

      fgXAnb = nb;
      fgXArr = ar;
      fgXArt = 0;
      fgXAct = (char*) xact;
      th->SetComment(fgXAct);

      if (condimp) condimp->Wait();
      condmutex->UnLock();

      if (iret) *iret = fgXArt;
      fgXActMutex->UnLock();
      th->SetComment();
      return 1997;
   } else            //we are in the main thread
      return 0;
}

//______________________________________________________________________________
void TThread::XAction()
{
   // Static method called via the thread timer to execute in the main
   // thread certain commands. This to avoid sophisticated locking and
   // possible deadlocking.

   TConditionImp *condimp = fgXActCondi->fConditionImp;
   TMutexImp *condmutex = fgXActCondi->GetMutex()->fMutexImp;
   condmutex->Lock();

   char const acts[] = "PRTF CUPD CANV CDEL PDCD METH ERRO";
   enum { kPRTF = 0, kCUPD = 5, kCANV = 10, kCDEL = 15,
          kPDCD = 20, kMETH = 25, kERRO = 30 };
   int iact = strstr(acts, fgXAct) - acts;
   char *cmd = 0;

   switch (iact) {

      case kPRTF:
         printf("%s\n", (const char*)fgXArr[1]);
         fflush(stdout);
         break;

      case kERRO:
         {
            int level = (int)Long_t(fgXArr[1]);
            const char *location = (const char*)fgXArr[2];
            char *mess = (char*)fgXArr[3];
            if (level != kFatal)
               GetErrorHandler()(level, level >= gErrorAbortLevel, location, mess);
            else
               GetErrorHandler()(level, kTRUE, location, mess);
            delete [] mess;
         }
         break;

      case kCUPD:
         //((TCanvas *)fgXArr[1])->Update();
         cmd = Form("((TCanvas *)0x%lx)->Update();",(Long_t)fgXArr[1]);
         gROOT->ProcessLine(cmd);
         break;

      case kCANV:

         switch(fgXAnb) { // Over TCanvas constructors

            case 2:
               //((TCanvas*)fgXArr[1])->Constructor();
               cmd = Form("((TCanvas *)0x%lx)->Constructor();",(Long_t)fgXArr[1]);
               gROOT->ProcessLine(cmd);
               break;

            case 5:
               //((TCanvas*)fgXArr[1])->Constructor(
               //                 (char*)fgXArr[2],
               //                 (char*)fgXArr[3],
               //                *((Int_t*)(fgXArr[4])));
               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]);
               gROOT->ProcessLine(cmd);
               break;
            case 6:
               //((TCanvas*)fgXArr[1])->Constructor(
               //                 (char*)fgXArr[2],
               //                 (char*)fgXArr[3],
               //                *((Int_t*)(fgXArr[4])),
               //                *((Int_t*)(fgXArr[5])));
               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]);
               gROOT->ProcessLine(cmd);
               break;

            case 8:
               //((TCanvas*)fgXArr[1])->Constructor(
               //                 (char*)fgXArr[2],
               //                 (char*)fgXArr[3],
               //               *((Int_t*)(fgXArr[4])),
               //               *((Int_t*)(fgXArr[5])),
               //               *((Int_t*)(fgXArr[6])),
               //               *((Int_t*)(fgXArr[7])));
               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]);
               gROOT->ProcessLine(cmd);
               break;

         }
         break;

      case kCDEL:
         //((TCanvas*)fgXArr[1])->Destructor();
         cmd = Form("((TCanvas *)0x%lx)->Destructor();",(Long_t)fgXArr[1]);
         gROOT->ProcessLine(cmd);
         break;

      case kPDCD:
         ((TVirtualPad*) fgXArr[1])->Divide( *((Int_t*)(fgXArr[2])),
                                  *((Int_t*)(fgXArr[3])),
                                  *((Float_t*)(fgXArr[4])),
                                  *((Float_t*)(fgXArr[5])),
                                  *((Int_t*)(fgXArr[6])));
         break;
      case kMETH:
         ((TMethodCall *) fgXArr[1])->Execute((void*)(fgXArr[2]),(const char*)(fgXArr[3]));
         break;

      default:
         ::Error("TThread::XAction", "wrong case");
   }

   fgXAct = 0;
   if (condimp) condimp->Signal();
   condmutex->UnLock();
}


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TThreadTimer                                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
TThreadTimer::TThreadTimer(Long_t ms) : TTimer(ms, kTRUE)
{
   // Create thread timer.

   gSystem->AddTimer(this);
}

//______________________________________________________________________________
Bool_t TThreadTimer::Notify()
{
   // Periodically execute the TThread::XAxtion() method in the main thread.

   if (TThread::fgXAct) { TThread::XAction(); }
   Reset();

   return kFALSE;
}


//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  TThreadCleaner                                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
TThreadCleaner::~TThreadCleaner()
{
   // Call user clean up routines.

   TThread::CleanUp();
}
 TThread.cxx:1
 TThread.cxx:2
 TThread.cxx:3
 TThread.cxx:4
 TThread.cxx:5
 TThread.cxx:6
 TThread.cxx:7
 TThread.cxx:8
 TThread.cxx:9
 TThread.cxx:10
 TThread.cxx:11
 TThread.cxx:12
 TThread.cxx:13
 TThread.cxx:14
 TThread.cxx:15
 TThread.cxx:16
 TThread.cxx:17
 TThread.cxx:18
 TThread.cxx:19
 TThread.cxx:20
 TThread.cxx:21
 TThread.cxx:22
 TThread.cxx:23
 TThread.cxx:24
 TThread.cxx:25
 TThread.cxx:26
 TThread.cxx:27
 TThread.cxx:28
 TThread.cxx:29
 TThread.cxx:30
 TThread.cxx:31
 TThread.cxx:32
 TThread.cxx:33
 TThread.cxx:34
 TThread.cxx:35
 TThread.cxx:36
 TThread.cxx:37
 TThread.cxx:38
 TThread.cxx:39
 TThread.cxx:40
 TThread.cxx:41
 TThread.cxx:42
 TThread.cxx:43
 TThread.cxx:44
 TThread.cxx:45
 TThread.cxx:46
 TThread.cxx:47
 TThread.cxx:48
 TThread.cxx:49
 TThread.cxx:50
 TThread.cxx:51
 TThread.cxx:52
 TThread.cxx:53
 TThread.cxx:54
 TThread.cxx:55
 TThread.cxx:56
 TThread.cxx:57
 TThread.cxx:58
 TThread.cxx:59
 TThread.cxx:60
 TThread.cxx:61
 TThread.cxx:62
 TThread.cxx:63
 TThread.cxx:64
 TThread.cxx:65
 TThread.cxx:66
 TThread.cxx:67
 TThread.cxx:68
 TThread.cxx:69
 TThread.cxx:70
 TThread.cxx:71
 TThread.cxx:72
 TThread.cxx:73
 TThread.cxx:74
 TThread.cxx:75
 TThread.cxx:76
 TThread.cxx:77
 TThread.cxx:78
 TThread.cxx:79
 TThread.cxx:80
 TThread.cxx:81
 TThread.cxx:82
 TThread.cxx:83
 TThread.cxx:84
 TThread.cxx:85
 TThread.cxx:86
 TThread.cxx:87
 TThread.cxx:88
 TThread.cxx:89
 TThread.cxx:90
 TThread.cxx:91
 TThread.cxx:92
 TThread.cxx:93
 TThread.cxx:94
 TThread.cxx:95
 TThread.cxx:96
 TThread.cxx:97
 TThread.cxx:98
 TThread.cxx:99
 TThread.cxx:100
 TThread.cxx:101
 TThread.cxx:102
 TThread.cxx:103
 TThread.cxx:104
 TThread.cxx:105
 TThread.cxx:106
 TThread.cxx:107
 TThread.cxx:108
 TThread.cxx:109
 TThread.cxx:110
 TThread.cxx:111
 TThread.cxx:112
 TThread.cxx:113
 TThread.cxx:114
 TThread.cxx:115
 TThread.cxx:116
 TThread.cxx:117
 TThread.cxx:118
 TThread.cxx:119
 TThread.cxx:120
 TThread.cxx:121
 TThread.cxx:122
 TThread.cxx:123
 TThread.cxx:124
 TThread.cxx:125
 TThread.cxx:126
 TThread.cxx:127
 TThread.cxx:128
 TThread.cxx:129
 TThread.cxx:130
 TThread.cxx:131
 TThread.cxx:132
 TThread.cxx:133
 TThread.cxx:134
 TThread.cxx:135
 TThread.cxx:136
 TThread.cxx:137
 TThread.cxx:138
 TThread.cxx:139
 TThread.cxx:140
 TThread.cxx:141
 TThread.cxx:142
 TThread.cxx:143
 TThread.cxx:144
 TThread.cxx:145
 TThread.cxx:146
 TThread.cxx:147
 TThread.cxx:148
 TThread.cxx:149
 TThread.cxx:150
 TThread.cxx:151
 TThread.cxx:152
 TThread.cxx:153
 TThread.cxx:154
 TThread.cxx:155
 TThread.cxx:156
 TThread.cxx:157
 TThread.cxx:158
 TThread.cxx:159
 TThread.cxx:160
 TThread.cxx:161
 TThread.cxx:162
 TThread.cxx:163
 TThread.cxx:164
 TThread.cxx:165
 TThread.cxx:166
 TThread.cxx:167
 TThread.cxx:168
 TThread.cxx:169
 TThread.cxx:170
 TThread.cxx:171
 TThread.cxx:172
 TThread.cxx:173
 TThread.cxx:174
 TThread.cxx:175
 TThread.cxx:176
 TThread.cxx:177
 TThread.cxx:178
 TThread.cxx:179
 TThread.cxx:180
 TThread.cxx:181
 TThread.cxx:182
 TThread.cxx:183
 TThread.cxx:184
 TThread.cxx:185
 TThread.cxx:186
 TThread.cxx:187
 TThread.cxx:188
 TThread.cxx:189
 TThread.cxx:190
 TThread.cxx:191
 TThread.cxx:192
 TThread.cxx:193
 TThread.cxx:194
 TThread.cxx:195
 TThread.cxx:196
 TThread.cxx:197
 TThread.cxx:198
 TThread.cxx:199
 TThread.cxx:200
 TThread.cxx:201
 TThread.cxx:202
 TThread.cxx:203
 TThread.cxx:204
 TThread.cxx:205
 TThread.cxx:206
 TThread.cxx:207
 TThread.cxx:208
 TThread.cxx:209
 TThread.cxx:210
 TThread.cxx:211
 TThread.cxx:212
 TThread.cxx:213
 TThread.cxx:214
 TThread.cxx:215
 TThread.cxx:216
 TThread.cxx:217
 TThread.cxx:218
 TThread.cxx:219
 TThread.cxx:220
 TThread.cxx:221
 TThread.cxx:222
 TThread.cxx:223
 TThread.cxx:224
 TThread.cxx:225
 TThread.cxx:226
 TThread.cxx:227
 TThread.cxx:228
 TThread.cxx:229
 TThread.cxx:230
 TThread.cxx:231
 TThread.cxx:232
 TThread.cxx:233
 TThread.cxx:234
 TThread.cxx:235
 TThread.cxx:236
 TThread.cxx:237
 TThread.cxx:238
 TThread.cxx:239
 TThread.cxx:240
 TThread.cxx:241
 TThread.cxx:242
 TThread.cxx:243
 TThread.cxx:244
 TThread.cxx:245
 TThread.cxx:246
 TThread.cxx:247
 TThread.cxx:248
 TThread.cxx:249
 TThread.cxx:250
 TThread.cxx:251
 TThread.cxx:252
 TThread.cxx:253
 TThread.cxx:254
 TThread.cxx:255
 TThread.cxx:256
 TThread.cxx:257
 TThread.cxx:258
 TThread.cxx:259
 TThread.cxx:260
 TThread.cxx:261
 TThread.cxx:262
 TThread.cxx:263
 TThread.cxx:264
 TThread.cxx:265
 TThread.cxx:266
 TThread.cxx:267
 TThread.cxx:268
 TThread.cxx:269
 TThread.cxx:270
 TThread.cxx:271
 TThread.cxx:272
 TThread.cxx:273
 TThread.cxx:274
 TThread.cxx:275
 TThread.cxx:276
 TThread.cxx:277
 TThread.cxx:278
 TThread.cxx:279
 TThread.cxx:280
 TThread.cxx:281
 TThread.cxx:282
 TThread.cxx:283
 TThread.cxx:284
 TThread.cxx:285
 TThread.cxx:286
 TThread.cxx:287
 TThread.cxx:288
 TThread.cxx:289
 TThread.cxx:290
 TThread.cxx:291
 TThread.cxx:292
 TThread.cxx:293
 TThread.cxx:294
 TThread.cxx:295
 TThread.cxx:296
 TThread.cxx:297
 TThread.cxx:298
 TThread.cxx:299
 TThread.cxx:300
 TThread.cxx:301
 TThread.cxx:302
 TThread.cxx:303
 TThread.cxx:304
 TThread.cxx:305
 TThread.cxx:306
 TThread.cxx:307
 TThread.cxx:308
 TThread.cxx:309
 TThread.cxx:310
 TThread.cxx:311
 TThread.cxx:312
 TThread.cxx:313
 TThread.cxx:314
 TThread.cxx:315
 TThread.cxx:316
 TThread.cxx:317
 TThread.cxx:318
 TThread.cxx:319
 TThread.cxx:320
 TThread.cxx:321
 TThread.cxx:322
 TThread.cxx:323
 TThread.cxx:324
 TThread.cxx:325
 TThread.cxx:326
 TThread.cxx:327
 TThread.cxx:328
 TThread.cxx:329
 TThread.cxx:330
 TThread.cxx:331
 TThread.cxx:332
 TThread.cxx:333
 TThread.cxx:334
 TThread.cxx:335
 TThread.cxx:336
 TThread.cxx:337
 TThread.cxx:338
 TThread.cxx:339
 TThread.cxx:340
 TThread.cxx:341
 TThread.cxx:342
 TThread.cxx:343
 TThread.cxx:344
 TThread.cxx:345
 TThread.cxx:346
 TThread.cxx:347
 TThread.cxx:348
 TThread.cxx:349
 TThread.cxx:350
 TThread.cxx:351
 TThread.cxx:352
 TThread.cxx:353
 TThread.cxx:354
 TThread.cxx:355
 TThread.cxx:356
 TThread.cxx:357
 TThread.cxx:358
 TThread.cxx:359
 TThread.cxx:360
 TThread.cxx:361
 TThread.cxx:362
 TThread.cxx:363
 TThread.cxx:364
 TThread.cxx:365
 TThread.cxx:366
 TThread.cxx:367
 TThread.cxx:368
 TThread.cxx:369
 TThread.cxx:370
 TThread.cxx:371
 TThread.cxx:372
 TThread.cxx:373
 TThread.cxx:374
 TThread.cxx:375
 TThread.cxx:376
 TThread.cxx:377
 TThread.cxx:378
 TThread.cxx:379
 TThread.cxx:380
 TThread.cxx:381
 TThread.cxx:382
 TThread.cxx:383
 TThread.cxx:384
 TThread.cxx:385
 TThread.cxx:386
 TThread.cxx:387
 TThread.cxx:388
 TThread.cxx:389
 TThread.cxx:390
 TThread.cxx:391
 TThread.cxx:392
 TThread.cxx:393
 TThread.cxx:394
 TThread.cxx:395
 TThread.cxx:396
 TThread.cxx:397
 TThread.cxx:398
 TThread.cxx:399
 TThread.cxx:400
 TThread.cxx:401
 TThread.cxx:402
 TThread.cxx:403
 TThread.cxx:404
 TThread.cxx:405
 TThread.cxx:406
 TThread.cxx:407
 TThread.cxx:408
 TThread.cxx:409
 TThread.cxx:410
 TThread.cxx:411
 TThread.cxx:412
 TThread.cxx:413
 TThread.cxx:414
 TThread.cxx:415
 TThread.cxx:416
 TThread.cxx:417
 TThread.cxx:418
 TThread.cxx:419
 TThread.cxx:420
 TThread.cxx:421
 TThread.cxx:422
 TThread.cxx:423
 TThread.cxx:424
 TThread.cxx:425
 TThread.cxx:426
 TThread.cxx:427
 TThread.cxx:428
 TThread.cxx:429
 TThread.cxx:430
 TThread.cxx:431
 TThread.cxx:432
 TThread.cxx:433
 TThread.cxx:434
 TThread.cxx:435
 TThread.cxx:436
 TThread.cxx:437
 TThread.cxx:438
 TThread.cxx:439
 TThread.cxx:440
 TThread.cxx:441
 TThread.cxx:442
 TThread.cxx:443
 TThread.cxx:444
 TThread.cxx:445
 TThread.cxx:446
 TThread.cxx:447
 TThread.cxx:448
 TThread.cxx:449
 TThread.cxx:450
 TThread.cxx:451
 TThread.cxx:452
 TThread.cxx:453
 TThread.cxx:454
 TThread.cxx:455
 TThread.cxx:456
 TThread.cxx:457
 TThread.cxx:458
 TThread.cxx:459
 TThread.cxx:460
 TThread.cxx:461
 TThread.cxx:462
 TThread.cxx:463
 TThread.cxx:464
 TThread.cxx:465
 TThread.cxx:466
 TThread.cxx:467
 TThread.cxx:468
 TThread.cxx:469
 TThread.cxx:470
 TThread.cxx:471
 TThread.cxx:472
 TThread.cxx:473
 TThread.cxx:474
 TThread.cxx:475
 TThread.cxx:476
 TThread.cxx:477
 TThread.cxx:478
 TThread.cxx:479
 TThread.cxx:480
 TThread.cxx:481
 TThread.cxx:482
 TThread.cxx:483
 TThread.cxx:484
 TThread.cxx:485
 TThread.cxx:486
 TThread.cxx:487
 TThread.cxx:488
 TThread.cxx:489
 TThread.cxx:490
 TThread.cxx:491
 TThread.cxx:492
 TThread.cxx:493
 TThread.cxx:494
 TThread.cxx:495
 TThread.cxx:496
 TThread.cxx:497
 TThread.cxx:498
 TThread.cxx:499
 TThread.cxx:500
 TThread.cxx:501
 TThread.cxx:502
 TThread.cxx:503
 TThread.cxx:504
 TThread.cxx:505
 TThread.cxx:506
 TThread.cxx:507
 TThread.cxx:508
 TThread.cxx:509
 TThread.cxx:510
 TThread.cxx:511
 TThread.cxx:512
 TThread.cxx:513
 TThread.cxx:514
 TThread.cxx:515
 TThread.cxx:516
 TThread.cxx:517
 TThread.cxx:518
 TThread.cxx:519
 TThread.cxx:520
 TThread.cxx:521
 TThread.cxx:522
 TThread.cxx:523
 TThread.cxx:524
 TThread.cxx:525
 TThread.cxx:526
 TThread.cxx:527
 TThread.cxx:528
 TThread.cxx:529
 TThread.cxx:530
 TThread.cxx:531
 TThread.cxx:532
 TThread.cxx:533
 TThread.cxx:534
 TThread.cxx:535
 TThread.cxx:536
 TThread.cxx:537
 TThread.cxx:538
 TThread.cxx:539
 TThread.cxx:540
 TThread.cxx:541
 TThread.cxx:542
 TThread.cxx:543
 TThread.cxx:544
 TThread.cxx:545
 TThread.cxx:546
 TThread.cxx:547
 TThread.cxx:548
 TThread.cxx:549
 TThread.cxx:550
 TThread.cxx:551
 TThread.cxx:552
 TThread.cxx:553
 TThread.cxx:554
 TThread.cxx:555
 TThread.cxx:556
 TThread.cxx:557
 TThread.cxx:558
 TThread.cxx:559
 TThread.cxx:560
 TThread.cxx:561
 TThread.cxx:562
 TThread.cxx:563
 TThread.cxx:564
 TThread.cxx:565
 TThread.cxx:566
 TThread.cxx:567
 TThread.cxx:568
 TThread.cxx:569
 TThread.cxx:570
 TThread.cxx:571
 TThread.cxx:572
 TThread.cxx:573
 TThread.cxx:574
 TThread.cxx:575
 TThread.cxx:576
 TThread.cxx:577
 TThread.cxx:578
 TThread.cxx:579
 TThread.cxx:580
 TThread.cxx:581
 TThread.cxx:582
 TThread.cxx:583
 TThread.cxx:584
 TThread.cxx:585
 TThread.cxx:586
 TThread.cxx:587
 TThread.cxx:588
 TThread.cxx:589
 TThread.cxx:590
 TThread.cxx:591
 TThread.cxx:592
 TThread.cxx:593
 TThread.cxx:594
 TThread.cxx:595
 TThread.cxx:596
 TThread.cxx:597
 TThread.cxx:598
 TThread.cxx:599
 TThread.cxx:600
 TThread.cxx:601
 TThread.cxx:602
 TThread.cxx:603
 TThread.cxx:604
 TThread.cxx:605
 TThread.cxx:606
 TThread.cxx:607
 TThread.cxx:608
 TThread.cxx:609
 TThread.cxx:610
 TThread.cxx:611
 TThread.cxx:612
 TThread.cxx:613
 TThread.cxx:614
 TThread.cxx:615
 TThread.cxx:616
 TThread.cxx:617
 TThread.cxx:618
 TThread.cxx:619
 TThread.cxx:620
 TThread.cxx:621
 TThread.cxx:622
 TThread.cxx:623
 TThread.cxx:624
 TThread.cxx:625
 TThread.cxx:626
 TThread.cxx:627
 TThread.cxx:628
 TThread.cxx:629
 TThread.cxx:630
 TThread.cxx:631
 TThread.cxx:632
 TThread.cxx:633
 TThread.cxx:634
 TThread.cxx:635
 TThread.cxx:636
 TThread.cxx:637
 TThread.cxx:638
 TThread.cxx:639
 TThread.cxx:640
 TThread.cxx:641
 TThread.cxx:642
 TThread.cxx:643
 TThread.cxx:644
 TThread.cxx:645
 TThread.cxx:646
 TThread.cxx:647
 TThread.cxx:648
 TThread.cxx:649
 TThread.cxx:650
 TThread.cxx:651
 TThread.cxx:652
 TThread.cxx:653
 TThread.cxx:654
 TThread.cxx:655
 TThread.cxx:656
 TThread.cxx:657
 TThread.cxx:658
 TThread.cxx:659
 TThread.cxx:660
 TThread.cxx:661
 TThread.cxx:662
 TThread.cxx:663
 TThread.cxx:664
 TThread.cxx:665
 TThread.cxx:666
 TThread.cxx:667
 TThread.cxx:668
 TThread.cxx:669
 TThread.cxx:670
 TThread.cxx:671
 TThread.cxx:672
 TThread.cxx:673
 TThread.cxx:674
 TThread.cxx:675
 TThread.cxx:676
 TThread.cxx:677
 TThread.cxx:678
 TThread.cxx:679
 TThread.cxx:680
 TThread.cxx:681
 TThread.cxx:682
 TThread.cxx:683
 TThread.cxx:684
 TThread.cxx:685
 TThread.cxx:686
 TThread.cxx:687
 TThread.cxx:688
 TThread.cxx:689
 TThread.cxx:690
 TThread.cxx:691
 TThread.cxx:692
 TThread.cxx:693
 TThread.cxx:694
 TThread.cxx:695
 TThread.cxx:696
 TThread.cxx:697
 TThread.cxx:698
 TThread.cxx:699
 TThread.cxx:700
 TThread.cxx:701
 TThread.cxx:702
 TThread.cxx:703
 TThread.cxx:704
 TThread.cxx:705
 TThread.cxx:706
 TThread.cxx:707
 TThread.cxx:708
 TThread.cxx:709
 TThread.cxx:710
 TThread.cxx:711
 TThread.cxx:712
 TThread.cxx:713
 TThread.cxx:714
 TThread.cxx:715
 TThread.cxx:716
 TThread.cxx:717
 TThread.cxx:718
 TThread.cxx:719
 TThread.cxx:720
 TThread.cxx:721
 TThread.cxx:722
 TThread.cxx:723
 TThread.cxx:724
 TThread.cxx:725
 TThread.cxx:726
 TThread.cxx:727
 TThread.cxx:728
 TThread.cxx:729
 TThread.cxx:730
 TThread.cxx:731
 TThread.cxx:732
 TThread.cxx:733
 TThread.cxx:734
 TThread.cxx:735
 TThread.cxx:736
 TThread.cxx:737
 TThread.cxx:738
 TThread.cxx:739
 TThread.cxx:740
 TThread.cxx:741
 TThread.cxx:742
 TThread.cxx:743
 TThread.cxx:744
 TThread.cxx:745
 TThread.cxx:746
 TThread.cxx:747
 TThread.cxx:748
 TThread.cxx:749
 TThread.cxx:750
 TThread.cxx:751
 TThread.cxx:752
 TThread.cxx:753
 TThread.cxx:754
 TThread.cxx:755
 TThread.cxx:756
 TThread.cxx:757
 TThread.cxx:758
 TThread.cxx:759
 TThread.cxx:760
 TThread.cxx:761
 TThread.cxx:762
 TThread.cxx:763
 TThread.cxx:764
 TThread.cxx:765
 TThread.cxx:766
 TThread.cxx:767
 TThread.cxx:768
 TThread.cxx:769
 TThread.cxx:770
 TThread.cxx:771
 TThread.cxx:772
 TThread.cxx:773
 TThread.cxx:774
 TThread.cxx:775
 TThread.cxx:776
 TThread.cxx:777
 TThread.cxx:778
 TThread.cxx:779
 TThread.cxx:780
 TThread.cxx:781
 TThread.cxx:782
 TThread.cxx:783
 TThread.cxx:784
 TThread.cxx:785
 TThread.cxx:786
 TThread.cxx:787
 TThread.cxx:788
 TThread.cxx:789
 TThread.cxx:790
 TThread.cxx:791
 TThread.cxx:792
 TThread.cxx:793
 TThread.cxx:794
 TThread.cxx:795
 TThread.cxx:796
 TThread.cxx:797
 TThread.cxx:798
 TThread.cxx:799
 TThread.cxx:800
 TThread.cxx:801
 TThread.cxx:802
 TThread.cxx:803
 TThread.cxx:804
 TThread.cxx:805
 TThread.cxx:806
 TThread.cxx:807
 TThread.cxx:808
 TThread.cxx:809
 TThread.cxx:810
 TThread.cxx:811
 TThread.cxx:812
 TThread.cxx:813
 TThread.cxx:814
 TThread.cxx:815
 TThread.cxx:816
 TThread.cxx:817
 TThread.cxx:818
 TThread.cxx:819
 TThread.cxx:820
 TThread.cxx:821
 TThread.cxx:822
 TThread.cxx:823
 TThread.cxx:824
 TThread.cxx:825
 TThread.cxx:826
 TThread.cxx:827
 TThread.cxx:828
 TThread.cxx:829
 TThread.cxx:830
 TThread.cxx:831
 TThread.cxx:832
 TThread.cxx:833
 TThread.cxx:834
 TThread.cxx:835
 TThread.cxx:836
 TThread.cxx:837
 TThread.cxx:838
 TThread.cxx:839
 TThread.cxx:840
 TThread.cxx:841
 TThread.cxx:842
 TThread.cxx:843
 TThread.cxx:844
 TThread.cxx:845
 TThread.cxx:846
 TThread.cxx:847
 TThread.cxx:848
 TThread.cxx:849
 TThread.cxx:850
 TThread.cxx:851
 TThread.cxx:852
 TThread.cxx:853
 TThread.cxx:854
 TThread.cxx:855
 TThread.cxx:856
 TThread.cxx:857
 TThread.cxx:858
 TThread.cxx:859
 TThread.cxx:860
 TThread.cxx:861
 TThread.cxx:862
 TThread.cxx:863
 TThread.cxx:864
 TThread.cxx:865
 TThread.cxx:866
 TThread.cxx:867
 TThread.cxx:868
 TThread.cxx:869
 TThread.cxx:870
 TThread.cxx:871
 TThread.cxx:872
 TThread.cxx:873
 TThread.cxx:874
 TThread.cxx:875
 TThread.cxx:876
 TThread.cxx:877
 TThread.cxx:878
 TThread.cxx:879
 TThread.cxx:880
 TThread.cxx:881
 TThread.cxx:882
 TThread.cxx:883
 TThread.cxx:884
 TThread.cxx:885
 TThread.cxx:886
 TThread.cxx:887
 TThread.cxx:888
 TThread.cxx:889
 TThread.cxx:890
 TThread.cxx:891
 TThread.cxx:892
 TThread.cxx:893
 TThread.cxx:894
 TThread.cxx:895
 TThread.cxx:896
 TThread.cxx:897
 TThread.cxx:898
 TThread.cxx:899
 TThread.cxx:900
 TThread.cxx:901
 TThread.cxx:902
 TThread.cxx:903
 TThread.cxx:904
 TThread.cxx:905
 TThread.cxx:906
 TThread.cxx:907
 TThread.cxx:908
 TThread.cxx:909
 TThread.cxx:910
 TThread.cxx:911
 TThread.cxx:912
 TThread.cxx:913
 TThread.cxx:914
 TThread.cxx:915
 TThread.cxx:916
 TThread.cxx:917
 TThread.cxx:918
 TThread.cxx:919
 TThread.cxx:920
 TThread.cxx:921
 TThread.cxx:922
 TThread.cxx:923
 TThread.cxx:924
 TThread.cxx:925
 TThread.cxx:926
 TThread.cxx:927
 TThread.cxx:928
 TThread.cxx:929
 TThread.cxx:930
 TThread.cxx:931
 TThread.cxx:932
 TThread.cxx:933
 TThread.cxx:934
 TThread.cxx:935
 TThread.cxx:936
 TThread.cxx:937
 TThread.cxx:938
 TThread.cxx:939
 TThread.cxx:940
 TThread.cxx:941
 TThread.cxx:942
 TThread.cxx:943
 TThread.cxx:944
 TThread.cxx:945
 TThread.cxx:946
 TThread.cxx:947
 TThread.cxx:948
 TThread.cxx:949
 TThread.cxx:950
 TThread.cxx:951
 TThread.cxx:952
 TThread.cxx:953
 TThread.cxx:954
 TThread.cxx:955
 TThread.cxx:956
 TThread.cxx:957
 TThread.cxx:958
 TThread.cxx:959
 TThread.cxx:960
 TThread.cxx:961
 TThread.cxx:962
 TThread.cxx:963
 TThread.cxx:964
 TThread.cxx:965
 TThread.cxx:966
 TThread.cxx:967
 TThread.cxx:968
 TThread.cxx:969
 TThread.cxx:970
 TThread.cxx:971
 TThread.cxx:972
 TThread.cxx:973
 TThread.cxx:974
 TThread.cxx:975
 TThread.cxx:976
 TThread.cxx:977
 TThread.cxx:978
 TThread.cxx:979
 TThread.cxx:980
 TThread.cxx:981
 TThread.cxx:982
 TThread.cxx:983
 TThread.cxx:984
 TThread.cxx:985
 TThread.cxx:986
 TThread.cxx:987
 TThread.cxx:988
 TThread.cxx:989
 TThread.cxx:990
 TThread.cxx:991
 TThread.cxx:992
 TThread.cxx:993
 TThread.cxx:994
 TThread.cxx:995
 TThread.cxx:996
 TThread.cxx:997
 TThread.cxx:998
 TThread.cxx:999
 TThread.cxx:1000
 TThread.cxx:1001
 TThread.cxx:1002
 TThread.cxx:1003
 TThread.cxx:1004
 TThread.cxx:1005
 TThread.cxx:1006
 TThread.cxx:1007
 TThread.cxx:1008
 TThread.cxx:1009
 TThread.cxx:1010
 TThread.cxx:1011
 TThread.cxx:1012
 TThread.cxx:1013
 TThread.cxx:1014
 TThread.cxx:1015
 TThread.cxx:1016
 TThread.cxx:1017
 TThread.cxx:1018
 TThread.cxx:1019
 TThread.cxx:1020
 TThread.cxx:1021
 TThread.cxx:1022
 TThread.cxx:1023
 TThread.cxx:1024
 TThread.cxx:1025
 TThread.cxx:1026
 TThread.cxx:1027
 TThread.cxx:1028
 TThread.cxx:1029
 TThread.cxx:1030
 TThread.cxx:1031
 TThread.cxx:1032
 TThread.cxx:1033
 TThread.cxx:1034
 TThread.cxx:1035
 TThread.cxx:1036
 TThread.cxx:1037
 TThread.cxx:1038
 TThread.cxx:1039
 TThread.cxx:1040
 TThread.cxx:1041
 TThread.cxx:1042
 TThread.cxx:1043
 TThread.cxx:1044
 TThread.cxx:1045
 TThread.cxx:1046
 TThread.cxx:1047
 TThread.cxx:1048
 TThread.cxx:1049
 TThread.cxx:1050
 TThread.cxx:1051
 TThread.cxx:1052
 TThread.cxx:1053
 TThread.cxx:1054
 TThread.cxx:1055
 TThread.cxx:1056
 TThread.cxx:1057
 TThread.cxx:1058
 TThread.cxx:1059
 TThread.cxx:1060
 TThread.cxx:1061
 TThread.cxx:1062
 TThread.cxx:1063
 TThread.cxx:1064
 TThread.cxx:1065
 TThread.cxx:1066
 TThread.cxx:1067
 TThread.cxx:1068
 TThread.cxx:1069
 TThread.cxx:1070
 TThread.cxx:1071
 TThread.cxx:1072
 TThread.cxx:1073
 TThread.cxx:1074
 TThread.cxx:1075
 TThread.cxx:1076
 TThread.cxx:1077
 TThread.cxx:1078
 TThread.cxx:1079
 TThread.cxx:1080
 TThread.cxx:1081
 TThread.cxx:1082
 TThread.cxx:1083
 TThread.cxx:1084
 TThread.cxx:1085
 TThread.cxx:1086
 TThread.cxx:1087
 TThread.cxx:1088
 TThread.cxx:1089
 TThread.cxx:1090
 TThread.cxx:1091
 TThread.cxx:1092
 TThread.cxx:1093
 TThread.cxx:1094
 TThread.cxx:1095
 TThread.cxx:1096
 TThread.cxx:1097
 TThread.cxx:1098
 TThread.cxx:1099
 TThread.cxx:1100
 TThread.cxx:1101
 TThread.cxx:1102
 TThread.cxx:1103
 TThread.cxx:1104
 TThread.cxx:1105
 TThread.cxx:1106
 TThread.cxx:1107
 TThread.cxx:1108
 TThread.cxx:1109
 TThread.cxx:1110
 TThread.cxx:1111
 TThread.cxx:1112
 TThread.cxx:1113
 TThread.cxx:1114
 TThread.cxx:1115
 TThread.cxx:1116
 TThread.cxx:1117
 TThread.cxx:1118
 TThread.cxx:1119
 TThread.cxx:1120
 TThread.cxx:1121
 TThread.cxx:1122
 TThread.cxx:1123
 TThread.cxx:1124
 TThread.cxx:1125
 TThread.cxx:1126
 TThread.cxx:1127
 TThread.cxx:1128
 TThread.cxx:1129
 TThread.cxx:1130
 TThread.cxx:1131
 TThread.cxx:1132
 TThread.cxx:1133
 TThread.cxx:1134
 TThread.cxx:1135
 TThread.cxx:1136
 TThread.cxx:1137
 TThread.cxx:1138
 TThread.cxx:1139
 TThread.cxx:1140
 TThread.cxx:1141
 TThread.cxx:1142
 TThread.cxx:1143
 TThread.cxx:1144
 TThread.cxx:1145
 TThread.cxx:1146
 TThread.cxx:1147
 TThread.cxx:1148
 TThread.cxx:1149
 TThread.cxx:1150
 TThread.cxx:1151
 TThread.cxx:1152
 TThread.cxx:1153
 TThread.cxx:1154
 TThread.cxx:1155
 TThread.cxx:1156
 TThread.cxx:1157
 TThread.cxx:1158
 TThread.cxx:1159
 TThread.cxx:1160
 TThread.cxx:1161
 TThread.cxx:1162
 TThread.cxx:1163
 TThread.cxx:1164
 TThread.cxx:1165
 TThread.cxx:1166
 TThread.cxx:1167
 TThread.cxx:1168
 TThread.cxx:1169
 TThread.cxx:1170
 TThread.cxx:1171
 TThread.cxx:1172
 TThread.cxx:1173
 TThread.cxx:1174
 TThread.cxx:1175
 TThread.cxx:1176
 TThread.cxx:1177
 TThread.cxx:1178
 TThread.cxx:1179
 TThread.cxx:1180
 TThread.cxx:1181
 TThread.cxx:1182
 TThread.cxx:1183
 TThread.cxx:1184
 TThread.cxx:1185