/*------------------------------------------------------------------------*/
/*                                                                        */
/*  THREAD.H                                                              */
/*                                                                        */
/*  Copyright (c) 1993, 1994 Borland International                        */
/*  All Rights Reserved                                                   */
/*                                                                        */
/*  Defines the class TMutex and its nested class Lock.                   */
/*  Defines the class TCriticalSection and its nested class Lock.         */
/*  Defines the class TSync and its nested class Lock.                    */
/*  Defines the template TStaticSync and its nested class Lock.           */
/*  Defines the class TThread.                                            */
/*                                                                        */
/*------------------------------------------------------------------------*/

#if !defined( CLASSLIB_THREAD_H )
#define CLASSLIB_THREAD_H

#if !defined( __CSTRING_H )
#include <cstring.h>
#endif

#if defined( _Windows )
# if defined( __WINDOWS_H )
#   if !defined( STRICT )
#     error #define <windows.h> must be preceded by #define STRICT
#   endif
# else
#   define STRICT   
#   include <windows.h>
# endif
#elif defined( __OS2__ )
# if defined( __OS2_H )
#   if !defined( INCL_BASE )
#     error #include <os2.h> must be preceded by #define INCL_PM
#   endif
# else
#   define INCL_BASE
#   include <os2.h>
# endif
#endif

#if !defined( __CHECKS_H )
#include <checks.h>
#endif  // __CHECKS_H

#if !defined( CLASSLIB_DEFS_H )
#include <classlib/defs.h>
#endif

#if !defined(BI_MULTI_THREAD)
#error Thread classes require multi-threaded operating system.
#endif

#if defined( BI_CLASSLIB_NO_po )
#pragma option -po-
#endif

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  class TMutex;                                                         */
/*  class TMutex::Lock;                                                   */
/*                                                                        */
/*  TMutex provides a system-independent interface to critical            */
/*  sections in threads. With suitable underlying implementations the     */
/*  same code can be used under OS/2 and Windows NT.                      */
/*                                                                        */
/*  An object of type TMutex can be used in conjunction with              */
/*  objects of type TMutex::Lock to guarantee that only one               */
/*  thread can be executing any of the code sections protected by the     */
/*  lock at any given time.                                               */
/*                                                                        */
/*  The differences between the classes TCriticalSection and TMutex are   */
/*  that a timeout can be specified when creating a Lock on a TMutex      */
/*  object, and that a TMutex object has a HANDLE which can be used       */
/*  outside the class. This mirrors the distinction made in Windows NT    */
/*  between a CRITICALSECTION and a Mutex. Under NT a TCriticalSection    */
/*  object is much faster than a TMutex object. Under operating systems   */
/*  that don't make this distinction a TCriticalSection object can use    */
/*  the same underlying implementation as a TMutex, losing the speed      */
/*  advantage that it has under NT.                                       */
/*                                                                        */
/*  TMutex Public Interface                                               */
/*  ---------------------------------                                     */
/*                                                                        */
/*      TMutex();               Constructor. Takes no parameters.         */
/*                                                                        */
/*      ~TMutex();              Destructor.                               */
/*                                                                        */
/*      operator HANDLE() const; (NT)                                     */
/*      operator HMTX() const;   (OS/2)                                   */
/*                              Returns a handle to the TMutex object,    */
/*                              for use in OS calls that require it.      */
/*                                                                        */
/*      class Lock;             Handles locking and unlocking of          */
/*                              critical sections.                        */
/*                                                                        */
/*                                                                        */
/*  TMutex::Lock Public Interface                                         */
/*  ---------------------------------------                               */
/*                                                                        */
/*      Lock( const TMutex&,                                              */
/*            unsigned long timeOut = NoLimit );                          */
/*                                                                        */
/*                              Request a lock on the TCriticalSection    */
/*                              object. If no Lock object in a different  */
/*                              thread from the calling thread holds      */
/*                              a lock on that object the lock is         */
/*                              allowed and execution continues. If       */
/*                              another thread holds a lock on that       */
/*                              object the requesting thread is blocked   */
/*                              until the owning thread has released all  */
/*                              of its locks.                             */
/*                                                                        */
/*      ~Lock();                Releases the lock.                        */
/*                                                                        */
/*  Example                                                               */
/*  -------                                                               */
/*                                                                        */
/*      TMutex LockF;                                                     */
/*                                                                        */
/*      void f()                                                          */
/*      {                                                                 */
/*      TMutex::Lock lock(LockF);                                         */
/*      // critical processing goes here                                  */
/*      }                                                                 */
/*                                                                        */
/*  Only one thread of execution will be allowed to execute the critical  */
/*  code inside f() at any one time.                                      */
/*                                                                        */
/*------------------------------------------------------------------------*/

class TMutex
{

public:

#if defined( __WIN32__ )
    // Windows NT
    enum { NoLimit = -1 };
    typedef HANDLE THandle;
#elif defined( __OS2__ )
    // OS/2
    enum { NoLimit = SEM_INDEFINITE_WAIT };
    typedef HMTX THandle;
#endif

    TMutex();
    ~TMutex();

    operator THandle() const;   // HANDLE() under NT
                                // HMTX() under OS/2

    class Lock
    {
    public:
        Lock( const TMutex&, unsigned long timeOut = NoLimit );
        ~Lock();

        void Release();

    private:
        const TMutex& MutexObj;

    };

    friend Lock;

private:

    THandle Handle;

    TMutex( const TMutex& );
    const TMutex& operator = ( const TMutex& );

};


#if defined( __WIN32__ )

//------------------------------------------------
//
//  TMutex constructor
//
//  WIN32
//

inline TMutex::TMutex()
{
    Handle = ::CreateMutex( 0, FALSE, 0 );
}

//------------------------------------------------
//
//  TMutex destructor
//
//  WIN32
//

inline TMutex::~TMutex()
{
    ::CloseHandle(Handle);
}

//------------------------------------------------
//
//  TMutex::operator THandle()
//
//  WIN32
//

inline TMutex::operator TMutex::THandle() const
{
    return Handle;
}

//------------------------------------------------
//
//  TMutex::Lock constructor
//
//  WIN32
//

inline TMutex::Lock::Lock( const TMutex& mutex, unsigned long timeOut ) :
    MutexObj(mutex)
{
    ::WaitForSingleObject( MutexObj, timeOut );
}

//------------------------------------------------
//
//  TMutex::Lock destructor
//
//  WIN32
//

inline TMutex::Lock::~Lock()
{
    Release();
}

//------------------------------------------------
//
//  TMutex::Lock::Release()
//
//  WIN32
//

inline void TMutex::Lock::Release()
{
    ::ReleaseMutex(MutexObj);
}

#elif defined( __OS2__ )

//------------------------------------------------
//
//  TMutex constructor
//
//  OS/2
//

inline TMutex::TMutex()
{
    ::DosCreateMutexSem( 0, &Handle, 0, FALSE );
}

//------------------------------------------------
//
//  TMutex destructor
//
//  OS/2
//

inline TMutex::~TMutex()
{
    ::DosCloseMutexSem(Handle);
}

//------------------------------------------------
//
//  TMutex::operator THandle()
//
//  OS/2
//

inline TMutex::operator TMutex::THandle() const
{
    return Handle;
}

//------------------------------------------------
//
//  TMutex::Lock constructor
//
//  OS/2
//

inline TMutex::Lock::Lock( const TMutex& mutex, unsigned long timeOut ) :
    MutexObj(mutex)
{
    ::DosRequestMutexSem( MutexObj, timeOut );
}

//------------------------------------------------
//
//  TMutex::Lock destructor
//
//  OS/2
//

inline TMutex::Lock::~Lock()
{
    Release();
}

//------------------------------------------------
//
//  TMutex::Lock::Release()
//
//  OS/2
//

inline void TMutex::Lock::Release()
{
    ::DosReleaseMutexSem(MutexObj);
}

#endif

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  class TCriticalSection;                                               */
/*  class TCriticalSection::Lock;                                         */
/*                                                                        */
/*  TCriticalSection provides a system-independent interface to critical  */
/*  sections in threads. With suitable underlying implementations the     */
/*  same code can be used under OS/2 and Windows NT.                      */
/*                                                                        */
/*  An object of type TCriticalSection can be used in conjunction with    */
/*  objects of type TCriticalSection::Lock to guarantee that only one     */
/*  thread can be executing any of the code sections protected by the     */
/*  lock at any given time.                                               */
/*                                                                        */
/*  The differences between the classes TCriticalSection and TMutex are   */
/*  that a timeout can be specified when creating a Lock on a TMutex      */
/*  object, and that a TMutex object has a HANDLE which can be used       */
/*  outside the class. This mirrors the distinction made in Windows NT    */
/*  between a CRITICALSECTION and a Mutex. Under NT a TCriticalSection    */
/*  object is much faster than a TMutex object. Under operating systems   */
/*  that don't make this distinction a TCriticalSection object can use    */
/*  the same underlying implementation as a TMutex, losing the speed      */
/*  advantage that it has under NT.                                       */
/*                                                                        */
/*  TCriticalSection Public Interface                                     */
/*  ---------------------------------                                     */
/*                                                                        */
/*      TCriticalSection();     Constructor. Takes no parameters.         */
/*                                                                        */
/*      ~TCriticalSection();    Destructor.                               */
/*                                                                        */
/*      class Lock;             Handles locking and unlocking of          */
/*                              critical sections.                        */
/*                                                                        */
/*  TCriticalSection::Lock Public Interface                               */
/*  ---------------------------------------                               */
/*                                                                        */
/*      Lock( const TCriticalSection& );                                  */
/*                                                                        */
/*                              Request a lock on the TCriticalSection    */
/*                              object. If no Lock object in a different  */
/*                              thread from the calling thread holds      */
/*                              a lock on that object the lock is         */
/*                              allowed and execution continues. If       */
/*                              another thread holds a lock on that       */
/*                              object the requesting thread is blocked   */
/*                              until the owning thread has released all  */
/*                              of its locks.                             */
/*                                                                        */
/*      ~Lock();                Releases the lock.                        */
/*                                                                        */
/*  Example                                                               */
/*  -------                                                               */
/*                                                                        */
/*      TCriticalSection LockF;                                           */
/*                                                                        */
/*      void f()                                                          */
/*      {                                                                 */
/*      TCriticalSection::Lock lock(LockF);                               */
/*      // critical processing goes here                                  */
/*      }                                                                 */
/*                                                                        */
/*  Only one thread of execution will be allowed to execute the critical  */
/*  code inside f() at any one time.                                      */
/*                                                                        */
/*------------------------------------------------------------------------*/

class TCriticalSection
{

public:

    TCriticalSection();
    ~TCriticalSection();

    class Lock
    {
    public:
        Lock( const TCriticalSection& );
        ~Lock();
    private:
#if defined( __WIN32__ )
        const TCriticalSection& CritSecObj;
#elif defined( __OS2__ )
        TMutex::Lock Lck;
#endif
    };

    friend Lock;

private:

#if defined( __WIN32__ )
    CRITICAL_SECTION CritSec;
#elif defined( __OS2__ )
    TMutex CritSec;
#endif

    TCriticalSection( const TCriticalSection& );
    const TCriticalSection& operator = ( const TCriticalSection& );

};


#if defined( __WIN32__ )

//------------------------------------------------
//
//  TCriticalSection constructor
//
//  WIN32
//
//  Use system call to initialize the CRITICAL_SECTION object.
//

inline TCriticalSection::TCriticalSection()
{
    ::InitializeCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSec));
}

//------------------------------------------------
//
//  TCriticalSection destructor
//
//  WIN32
//
//  Use system call to destroy the CRITICAL_SECTION object.
//

inline TCriticalSection::~TCriticalSection()
{
    ::DeleteCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSec));
}

//------------------------------------------------
//
//  TCriticalSection::Lock constructor
//
//  WIN32
//
//  Use system call to lock the CRITICAL_SECTION object.
//

inline TCriticalSection::Lock::Lock( const TCriticalSection& sec ) :
    CritSecObj(sec)
{
    ::EnterCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSecObj.CritSec));
}

//------------------------------------------------
//
//  TCriticalSection::Lock destructor
//
//  WIN32
//
//  Use system call to unlock the CRITICAL_SECTION object.
//

inline TCriticalSection::Lock::~Lock()
{
    ::LeaveCriticalSection(CONST_CAST(CRITICAL_SECTION *,&CritSecObj.CritSec));
}

#elif defined( __OS2__ )

//------------------------------------------------
//
//  TCriticalSection constructor
//
//  OS2
//
//  Compiler takes care of constructing the TMutex data object.
//

inline TCriticalSection::TCriticalSection()
{
}

//------------------------------------------------
//
//  TCriticalSection destructor
//
//  OS2
//
//  Compiler takes care of destroying the TMutex data object.
//

inline TCriticalSection::~TCriticalSection()
{
}

//------------------------------------------------
//
//  TCriticalSection::Lock constructor
//
//  OS2
//
//  Construct the TMutex::Lock object to lock the
//  specified TCriticalSection object.
//

inline TCriticalSection::Lock::Lock( const TCriticalSection& sec ) :
    Lck(sec.CritSec)
{
}

//------------------------------------------------
//
//  TCriticalSection::Lock destructor
//
//  OS2
//
//  Compiler takes care of destroying the TMutex::Lock data
//  object, which releases the lock.
//

inline TCriticalSection::Lock::~Lock()
{
}

#endif

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  class TSync;                                                          */
/*  class TSync::Lock;                                                    */
/*                                                                        */
/*  TSync provides a system-independent interface to build classes        */
/*  that act like monitors, i.e., classes in which only one member        */
/*  can execute on a particular instance at any one time. TSync uses      */
/*  TCriticalSection, so it is portable to all platforms that             */
/*  TCriticalSection has been ported to.                                  */
/*                                                                        */
/*  TSync Public Interface                                                */
/*  -------------------------                                             */
/*                                                                        */
/*  None. TSync can only be a base class.                                 */
/*                                                                        */
/*  TSync Protected Interface                                             */
/*  ----------------------------                                          */
/*                                                                        */
/*      TSync( const TSync& );                                            */
/*                              Copy constructor. Does not copy the       */
/*                              TCriticalSection object.                  */
/*                                                                        */
/*      const TSync& operator = ( const TSync& );                         */
/*                              Assignment operator. Does not copy the    */
/*                              TCriticalSection object.                  */
/*                                                                        */
/*      class Lock;             Handles locking and unlocking of member   */
/*                              functions.                                */
/*                                                                        */
/*  Example                                                               */
/*  -------                                                               */
/*                                                                        */
/*                                                                        */
/*      class ThreadSafe : private TSync                                  */
/*      {                                                                 */
/*      public:                                                           */
/*          void f();                                                     */
/*          void g();                                                     */
/*      private:                                                          */
/*          int i;                                                        */
/*      };                                                                */
/*                                                                        */
/*      void ThreadSafe::f()                                              */
/*      {                                                                 */
/*      Lock lock(this);                                                       */
/*      if( i == 2 )                                                      */
/*          i = 3;                                                        */
/*      }                                                                 */
/*                                                                        */
/*      void ThreadSafe::g()                                              */
/*      {                                                                 */
/*      Lock lock(this);                                                       */
/*      if( i == 3 )                                                      */
/*          i = 2;                                                        */
/*      }                                                                 */
/*                                                                        */
/*------------------------------------------------------------------------*/

class TSync
{

protected:

    TSync();
    TSync( const TSync& );
    const TSync& operator = ( const TSync& );

    class Lock : private TCriticalSection::Lock
    {
    public:
        Lock( const TSync * );
    private:
        static const TCriticalSection& GetRef( const TSync * );
    };

    friend Lock;

private:

    TCriticalSection CritSec;

};

//------------------------------------------------
//
//  TSync constructors
//
//  Copy constructor does not copy the TCriticalSection object,
//  since the new object is not being used in any of its own
//  member functions. This means that the new object must start
//  in an unlocked state.
//

inline TSync::TSync()
{
}

inline TSync::TSync( const TSync& )
{
}

//------------------------------------------------
//
//  TSync assignment operator
//
//  Does not copy the TCriticalSection object, since the new
//  object is not being used in any of its own member functions.
//  This means that the new object must start in an unlocked state.
//

inline const TSync& TSync::operator = ( const TSync& )
{
    return *this;
}

//------------------------------------------------
//
//  TSync::Lock constructor
//
//  Locks the TCriticalSection object in the TSync object.
//

inline TSync::Lock::Lock( const TSync *sync ) :
    TCriticalSection::Lock(GetRef(sync))
{
}

//------------------------------------------------
//
//  TSync::Lock::GetRef()
//
//  Returns a reference to the TCriticalSection object contained
//  in the TSync object.
//
//  In the diagnostic version, checks for a null pointer.
//

inline const TCriticalSection& TSync::Lock::GetRef( const TSync *sync )
{
    CHECK( sync != 0 );
    return sync->CritSec;
}

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  template <class T> class TStaticSync;                                 */
/*  template <class T> class TStaticSync::Lock;                           */
/*                                                                        */
/*  TStaticSync provides a system-independent interface to build sets     */
/*  of classes that act somewhat like monitors, i.e., classes in which    */
/*  only one member function can execute at any one time regardless of    */
/*  which instance it is being called on. TStaticSync uses                */
/*  TCriticalSection, so it is portable to all platforms that             */
/*  TCriticalSection has been ported to.                                  */
/*                                                                        */
/*  TStaticSync Public Interface                                          */
/*  -------------------------                                             */
/*                                                                        */
/*  None. TStaticSync can only be a base class.                           */
/*                                                                        */
/*  TStaticSync Protected Interface                                       */
/*  ----------------------------                                          */
/*                                                                        */
/*      TStaticSync<T>( const TStaticSync<T>& );                          */
/*                              Copy constructor. Does not copy the       */
/*                              TCriticalSection object.                  */
/*                                                                        */
/*      const TStaticSync<T>& operator = ( const TStaticSync<T>& );       */
/*                              Assignment operator. Does not copy the    */
/*                              TCriticalSection object.                  */
/*                                                                        */
/*      class Lock;             Handles locking and unlocking of member   */
/*                              functions.                                */
/*                                                                        */
/*  Example                                                               */
/*  -------                                                               */
/*                                                                        */
/*                                                                        */
/*      class ThreadSafe : private TStaticSync<ThreadSafe>                */
/*      {                                                                 */
/*      public:                                                           */
/*          void f();                                                     */
/*          void g();                                                     */
/*      private:                                                          */
/*          static int i;                                                 */
/*      };                                                                */
/*                                                                        */
/*      void ThreadSafe::f()                                              */
/*      {                                                                 */
/*      Lock lock;                                                        */
/*      if( i == 2 )                                                      */
/*          i = 3;                                                        */
/*      }                                                                 */
/*                                                                        */
/*      void ThreadSafe::g()                                              */
/*      {                                                                 */
/*      Lock lock;                                                        */
/*      if( i == 3 )                                                      */
/*          i = 2;                                                        */
/*      }                                                                 */
/*                                                                        */
/*------------------------------------------------------------------------*/

template <class T> class TStaticSync
{

protected:

    TStaticSync();
    TStaticSync( const TStaticSync<T>& );
    const TStaticSync<T>& operator = ( const TStaticSync<T>& );
    ~TStaticSync();

    class Lock : private TCriticalSection::Lock
    {
    public:
        Lock() : TCriticalSection::Lock(*TStaticSync<T>::CritSec) {}
    };

    friend Lock;

private:

    static TCriticalSection *CritSec;
    static unsigned long Count;

};

//------------------------------------------------
//
//  TStaticSync<T>::CritSec
//  TStaticSync<T>::Count
//
//  Instantiate the data members.
//

template <class T> TCriticalSection *TStaticSync<T>::CritSec;
template <class T> unsigned long TStaticSync<T>::Count;

//------------------------------------------------
//
//  TStaticSync<T> constructor
//
//  If this is the first TStaticSync<T> object to be constructed,
//  create the semaphore.
//
//  The copy constructor only has to increment the count, since
//  there will already be at least one TStaticSync<T> object,
//  namely, the one being copied.
//

template <class T> inline TStaticSync<T>::TStaticSync()
{
    if( Count++ == 0 )
        CritSec = new TCriticalSection;
}

template <class T>
inline TStaticSync<T>::TStaticSync( const TStaticSync<T>& )
{
    Count++;
}

//------------------------------------------------
//
//  TStaticSync<T> assignment operator
//

template <class T>
inline const TStaticSync<T>& TStaticSync<T>::operator = ( const TStaticSync<T>& )
{
    return *this;
}

//------------------------------------------------
//
//  TStaticSync<T> destructor
//
//  If this is the only remaining TStaticSync<T> object,
//  destroy the semaphore.
//

template <class T> inline TStaticSync<T>::~TStaticSync()
{
    if( --Count == 0 )
        delete CritSec;
}

/*------------------------------------------------------------------------*/
/*                                                                        */
/*  class TThread;                                                        */
/*                                                                        */
/*  TThread provides a system-independent interface to threads. With      */
/*  suitable underlying implementations the same code can be used under   */
/*  OS/2 and Windows NT.                                                  */
/*                                                                        */
/*  TThread Public Interface                                              */
/*  ------------------------                                              */
/*                                                                        */
/*      Start();                Begins execution of the thread. Returns   */
/*                              the handle of the thread.                 */
/*                                                                        */
/*      Suspend();              Suspends execution of the thread.         */
/*      Resume();               Resumes execution of a suspended thread.  */
/*                                                                        */
/*      Terminate();            Sets an internal flag that indicates      */
/*                              that the thread should exit. The          */
/*                              derived class can check the state of      */
/*                              this flag by calling ShouldTerminate().   */
/*                                                                        */
/*      WaitForExit( unsigned long timeout = NoLimit );                   */
/*                              Blocks the calling thread until the       */
/*                              internal thread exits or until the time   */
/*                              specified by timeout, in milliseconds,    */
/*                              expires. A timeout of NoLimit says to     */
/*                              wait indefinitely.                        */
/*                                                                        */
/*      TerminateAndWait( unsigned long timeout = NoLimit );              */
/*                              Combines the behavior of Terminate() and  */
/*                              WaitForExit(). Sets an internal flag that */
/*                              indicates that the thread should exit     */
/*                              and blocks the calling thread until the   */
/*                              internal thread exits or until the time   */
/*                              specified by timeout, in milliseconds,    */
/*                              expires. A timeout of NoLimit says to     */
/*                              wait indefinitely.                        */
/*                                                                        */
/*      GetStatus();            Gets the current status of the thread.    */
/*                              See TThread::Status for possible values.  */
/*                                                                        */
/*      GetPriority();          Gets the priority of the thread.          */
/*      SetPriority();          Sets the priority of the thread.          */
/*                                                                        */
/*      enum Status;            Identifies the states that the class      */
/*                              can be in.                                */
/*                                                                        */
/*          Created             The class has been created but the        */
/*                              thread has not been started.              */
/*          Running             The thread is running.                    */
/*                                                                        */
/*          Suspended           The thread has been suspended.            */
/*                                                                        */
/*          Finished            The thread has finished execution.        */
/*                                                                        */
/*          Invalid             The object is invalid. Currently this     */
/*                              happens only when the operating system    */
/*                              is unable to start the thread.            */
/*                                                                        */
/*      class ThreadError;      The error class that defines the objects  */
/*                              that are thrown when an error occurs.     */
/*                                                                        */
/*  TThread::ThreadError Public Interface                                 */
/*  -------------------------------------                                 */
/*                                                                        */
/*      enum ErrorType;         Identifies the type of error that         */
/*                              occurred.                                 */
/*                                                                        */
/*          SuspendBeforeRun    The user called Suspend() on an object    */
/*                              before calling Start().                   */
/*                                                                        */
/*          ResumeBeforeRun     The user called Resume() on an object     */
/*                              before calling Start().                   */
/*                                                                        */
/*          ResumeDuringRun     The user called Resume() on a thread that */
/*                              was not Suspended.                        */
/*                                                                        */
/*          SuspendAfterExit    The user called Suspend() on an object    */
/*                              whose thread had already exited.          */
/*                                                                        */
/*          ResumeAfterExit     The user called Resume() on an object     */
/*                              whose thread had already exited.          */
/*                                                                        */
/*          CreationFailure     The operating system was unable to create */
/*                              the thread.                               */
/*                                                                        */
/*          DestroyBeforeExit   The object's destructor was invoked       */
/*                              its thread had exited.                    */
/*                                                                        */
/*          AssignError         An attempt was made to assign to an       */
/*                              object that was not in either the         */
/*                              Created or the Finished state.            */
/*                                                                        */
/*      ErrorType GetErrorType() const;                                   */
/*                              Returns a code indicating the type of     */
/*                              error that occurred.                      */
/*                                                                        */
/*      string why();           Returns a string that describes the       */
/*                              error. Inherited from xmsg.               */
/*                                                                        */
/*  TThread Protected Interface                                           */
/*  ---------------------------                                           */
/*                                                                        */
/*      TThread();              Creates an object of type TThread.        */
/*      virtual ~TThread();     Destroys the object.                      */
/*                                                                        */
/*      const TThread& operator = ( const TThread& );                     */
/*                              The target object must be in either the   */
/*                              Created state or the Finished state. If   */
/*                              so, puts the object into the Created      */
/*                              state. If the object is not in either the */
/*                              Created state or the Finished state it    */
/*                              is an error and an exception will be      */
/*                              thrown.                                   */
/*                                                                        */
/*      TThread( const TThread& );                                        */
/*                              Pts the object into the Created           */
/*                              state, just like the default constructor. */
/*                              Does not copy any of the internal details */
/*                              of the thread being copied.               */
/*                                                                        */
/*      virtual unsigned long Run() = 0;                                  */
/*                              The function that does the work. Calling  */
/*                              Start() creates a thread that begins      */
/*                              executing Run() with the 'this' pointer   */
/*                              pointing to the TThread-based object.     */
/*                                                                        */
/*      int ShouldTerminate() const;                                      */
/*                              Returns a non-zero value to indicate      */
/*                              that Terminate() or TerminateAndWait()    */
/*                              has been called. If this capability is    */
/*                              being used, the thread should call        */
/*                              ShouldTerminate() regularly, and if it    */
/*                              returns a non-zero value the thread       */
/*                              finish its processing and exit.           */
/*                                                                        */
/*  Example                                                               */
/*  -------                                                               */
/*                                                                        */
/*      class TimerThread : public TThread                                */
/*      {                                                                 */
/*      public:                                                           */
/*          TimerThread() : Count(0) {}                                   */
/*      private:                                                          */
/*          unsigned long Run();                                          */
/*          int Count;                                                    */
/*      };                                                                */
/*                                                                        */
/*      unsigned long TimerThread::Run()                                  */
/*      {                                                                 */
/*      // loop 10 times                                                  */
/*      while( Count++ < 10 )                                             */
/*          {                                                             */
/*          Sleep(1000);    // delay 1 second                             */
/*          cout << "Iteration " << Count << endl;                        */
/*          }                                                             */
/*      return 0L;                                                        */
/*      }                                                                 */
/*                                                                        */
/*      int main()                                                        */
/*      {                                                                 */
/*      TimerThread timer;                                                */
/*      timer.Start();                                                    */
/*      Sleep( 20000 );     // delay 20 seconds                           */
/*      return 0;                                                         */
/*      }                                                                 */
/*                                                                        */
/*  Internal States                                                       */
/*  ---------------                                                       */
/*                                                                        */
/*  Created :   the object has been created but its thread has not been   */
/*              started. The only valid transition from this state is     */
/*              to Running, which happens on a call to Start(). In        */
/*              particular, a call to Suspend() or Resume() when the      */
/*              object is in this state is an error and will throw an     */
/*              exception.                                                */
/*                                                                        */
/*  Running:    the thread has been started successfully. There are two   */
/*              transitions from this state:                              */
/*                                                                        */
/*                  When the user calls Suspend() the object moves into   */
/*                  the Suspended state.                                  */
/*                                                                        */
/*                  When the thread exits the object moves into the       */
/*                  Finished state.                                       */
/*                                                                        */
/*              Calling Resume() on an object that is in the Running      */
/*              state is an error and will throw an exception.            */
/*                                                                        */
/*  Suspended:  the thread has been suspended by the user. Subsequent     */
/*              calls to Suspend() nest, so there must be as many calls   */
/*              to Resume() as there were to Suspend() before the thread  */
/*              actually resumes execution.                               */
/*                                                                        */
/*  Finished:   the thread has finished executing. There are no valid     */
/*              transitions out of this state. This is the only state     */
/*              from which it is legal to invoke the destructor for the   */
/*              object. Invoking the destructor when the object is in     */
/*              any other state is an error and will throw an exception.  */
/*                                                                        */
/*------------------------------------------------------------------------*/

class _BIDSCLASS TThread
{

public:

#if defined( __WIN32__ )
    // Windows NT
    enum { NoLimit = -1 };
    typedef HANDLE THandle;
#elif defined( __OS2__ )
    // OS/2
    enum { NoLimit = DCWW_WAIT };
    typedef TID THandle;
#endif

    enum Status { Created, Running, Suspended, Finished, Invalid };

    THandle Start();
    unsigned long Suspend();
    unsigned long Resume();
    void Terminate();
    unsigned long WaitForExit( unsigned long timeout = NoLimit );
    unsigned long TerminateAndWait( unsigned long timeout = NoLimit );

    Status GetStatus() const;

    int GetPriority() const;
    int SetPriority(int);

    class ThreadError : public xmsg
        {
        friend TThread;
        public:
            enum ErrorType
                {
                SuspendBeforeRun,
                ResumeBeforeRun,
                ResumeDuringRun,
                SuspendAfterExit,
                ResumeAfterExit,
                CreationFailure,
                DestroyBeforeExit,
                AssignError
                };
            ErrorType GetErrorType() const;
        private:
            ThreadError(ErrorType type);
            static string MakeString(ErrorType type );
            ErrorType Type;
        };

protected:

    TThread();

    // Copying a thread puts the target into the Created state
    TThread( const TThread& );
    const TThread& operator = ( const TThread& );

    virtual ~TThread();

    int ShouldTerminate() const;

private:

    virtual unsigned long Run() = 0;

    Status CheckStatus() const;

    THandle Handle;
#if defined( __MT__ )
    static void _USERENTRY Execute( void *thread );
#elif defined( __WIN32__ )
    static unsigned long _stdcall Execute( void *thread );
#else
    static void __stdcall Execute( unsigned long );
#endif
#if defined( __WIN32__ )
    DWORD ThreadId;
#else
    ULONG Priority;
#endif
    mutable Status Stat;

    int TerminationRequested;

};

//------------------------------------------------
//
//  TThread::GetStatus()
//
//  If the thread is marked as Running it may have terminated
//  without our knowing it, so we have to check.
//

#if defined( BI_NO_MUTABLE )
inline TThread::Status TThread::GetStatus() const
{
    if( Stat == Running )
        CONST_CAST(TThread *,this)->Stat = CheckStatus();
    return Stat;
}
#else
inline TThread::Status TThread::GetStatus() const
{
    if( Stat == Running )
        Stat = CheckStatus();
    return Stat;
}
#endif

//------------------------------------------------
//
//  TThread::GetPriority()
//
//  Direct OS call under WIN32. Return stored value under OS/2.
//

inline int TThread::GetPriority() const
{
#if defined( __WIN32__ )
    return ::GetThreadPriority(Handle);
#else
    return Priority;
#endif
}

//------------------------------------------------
//
//  TThread::ShouldTerminate()
//
inline int TThread::ShouldTerminate() const
{
    return TerminationRequested;
}

//------------------------------------------------
//
//  TThread::ThreadError::GetErrorType()
//

inline TThread::ThreadError::ErrorType TThread::ThreadError::GetErrorType() const
{
    return Type;
}

#if defined( BI_CLASSLIB_NO_po )
#pragma option -po.
#endif

#endif  // __THREAD_H


