//----------------------------------------------------------------------------
// Borland Class Library
// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
// Copyright (c) 1998 by Yura Bidus, All Rights Reserved
//
/// \file
/// - Defines the class TSemaphore and its nested class TLock.
/// - Defines the derived semaphore class TMutex
/// - Defines the derived semaphore class TCountedSemaphore
/// - Defines the derived semaphore class TEventSemaphore
/// - Defines the derived semaphore class TWaitableTimer
/// - Defined the semaphore set class TSemaphoreSet and its nested class TLock.
/// - Defines the class TCriticalSection and its nested class TLock.
/// - Defines the class TMRSWSection and its nested class TLock.
/// - Defines the class TSync and its nested class TLock.
/// - Defines the template TStaticSync and its nested class TLock.
/// - Defines the class TThread.
/// - Defines the class TTlsAllocator
/// - Defines the class TLocalObject
/// - Defines the class TLocalData
/// - Defines the class TTlsDataManager
/// - Defines the class TLocalObject
//----------------------------------------------------------------------------
 
#if !defined(OWL_THREAD_H)
#define OWL_THREAD_H
 
#include <owl/private/defs.h>
#if defined(BI_HAS_PRAGMA_ONCE)
# pragma once
#endif
 
#include <owl/defs.h>
 
#if !defined(BI_MULTI_THREAD)
#error Thread classes require multi-threaded operating system.
#endif
 
#include <owl/private/wsysinc.h>
#include <owl/wsyscls.h>
#include <owl/exbase.h>
 
#if defined(BI_MULTI_THREAD_RTL)
# include <owl/template.h>
# include <vector>
# include <algorithm>
#endif
 
namespace owl {
 
DIAG_DECLARE_GROUP(OwlThread);
 
/// \cond NoSuppressDoxygenWarning
#include <owl/preclass.h>
/// \endcond
 
/// \addtogroup utility_group
/// @{
 
//
/// \class TSemaphore
// ~~~~~ ~~~~~~~~~~
/// Base class for handle-based thread synchronization classes, TMutex,
/// TCountedSemaphore and TEventSemaphore. Defines some types & constants, as
/// well as holding the system object handle for Win32.
//
class _OWLCLASS TSemaphore{
  public:
    virtual ~TSemaphore();
 
    enum { NoWait = 0, NoLimit = INFINITE };
    typedef HANDLE THandle;
    operator THandle() const;
 
 
    class TLock {
      public:
        TLock(const TSemaphore&, ulong timeOut = NoLimit, bool alertable = false);
       ~TLock();
 
        bool WasAquired() const;  ///< See if really aquired, or just timed-out
 
        /// Release lock early & relinquish, i.e. before destructor. Or, just
        /// drop the lock count on an exiting semaphore & keep locked 'til dtor
        //
        void Release(bool relinquish = false);
 
      private:
        const TSemaphore* Sem;
    };
    friend class TLock;
    friend class _OWLCLASS TSemaphoreSet;
 
  protected:
    virtual void Release() = 0;  ///< Derived class must provide release
 
    THandle Handle;              ///< Derived class must initialize
};
 
//
/// \class TMutex
// ~~~~~ ~~~~~~
/// Mutual-exclusive semaphore
//
/// 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::TLock (inherited from TSemaphore) 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.
//
class _OWLCLASS TMutex : public TSemaphore{
  public:
    TMutex(LPCTSTR name = 0, LPSECURITY_ATTRIBUTES sa = 0);
    TMutex(const tstring& name, LPSECURITY_ATTRIBUTES sa = 0);
    TMutex(LPCTSTR name, bool inherit, uint32 access = MUTEX_ALL_ACCESS);
    TMutex(const tstring& name, bool inherit, uint32 access = MUTEX_ALL_ACCESS);
    TMutex(THandle handle);
 
    typedef TLock Lock;  ///< For compatibility with old T-less typename
 
    /// If another mutex with the same name existed when this mutex
    /// was created, then another handle to the object exists and
    /// someone else may be using it too.
    //
    bool IsShared();
 
  private:
    TMutex(const TMutex&);
    const TMutex& operator =(const TMutex&);
 
    virtual void Release();  ///< Release this mutex semaphore
 
    bool Shared;
 
};
 
//
/// \class TCountedSemaphore
// ~~~~~ ~~~~~~~~~~~~~~~~~
/// Counted semaphore. Currently Win32 only
//
class _OWLCLASS TCountedSemaphore : public TSemaphore{
  public:
    TCountedSemaphore(int initialCount, int maxCount, LPCTSTR name = 0,
                      LPSECURITY_ATTRIBUTES sa = 0);
    TCountedSemaphore(int initialCount, int maxCount, const tstring& name, LPSECURITY_ATTRIBUTES sa = 0);
    TCountedSemaphore(LPCTSTR name, bool inherit,
                      uint32 access = SEMAPHORE_ALL_ACCESS);
    TCountedSemaphore(const tstring& name, bool inherit, uint32 access = SEMAPHORE_ALL_ACCESS);
    TCountedSemaphore(THandle handle);
 
  private:
    TCountedSemaphore(const TCountedSemaphore&);
    const TCountedSemaphore& operator =(const TCountedSemaphore&);
 
    virtual void Release();  ///< Release this counted semaphore
};
 
//
/// \class TEventSemaphore
// ~~~~~ ~~~~~~~~~~~~~~~
//
class _OWLCLASS TEventSemaphore : public TSemaphore{
  public:
    TEventSemaphore(bool manualReset=false, bool initialState=false,
                    LPCTSTR name = 0, LPSECURITY_ATTRIBUTES sa = 0);
    TEventSemaphore(bool manualReset, bool initialState, const tstring& name, LPSECURITY_ATTRIBUTES sa = 0);
    TEventSemaphore(LPCTSTR name, bool inherit,
                    uint32 access = SEMAPHORE_ALL_ACCESS);
    TEventSemaphore(const tstring& name, bool inherit, uint32 access = SEMAPHORE_ALL_ACCESS);
    TEventSemaphore(THandle handle);
 
    void Set();
    void Reset();
    void Pulse();
 
 
  private:
    TEventSemaphore(const TMutex&);
    const TEventSemaphore& operator =(const TEventSemaphore&);
 
    virtual void Release();  ///< Release this event semaphore
 
};
 
//
/// \class TWaitableTimer
// ~~~~~ ~~~~~~~~~~~~~~
///  Encapsulation of Waitable Timer  over Borland Classlib TSemaphore hierarchy
//
//  Created by Marco Savegnago (msave) email: msave@tin.it
//
// additional typedef for old headers
#if !defined(CreateWaitableTimer)
typedef VOID (APIENTRY *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
#endif
 
 
class _OWLCLASS TWaitableTimer : public TSemaphore {
  public:
    TWaitableTimer(bool manualReset=false, LPCTSTR name = 0, LPSECURITY_ATTRIBUTES sa = 0);
    TWaitableTimer(bool manualReset, const tstring& name, LPSECURITY_ATTRIBUTES sa = 0);
    TWaitableTimer(LPCTSTR name, bool inherit = false,  uint32  dwDesiredAccess = FILE_ALL_ACCESS);
    TWaitableTimer(const tstring& name, bool inherit = false,  uint32  dwDesiredAccess = FILE_ALL_ACCESS);
    TWaitableTimer(THandle handle);
    virtual ~TWaitableTimer();
 
    bool Set(const TFileTime& duetime,  int32 period=0,PTIMERAPCROUTINE compFunc=0,
             void* param=0,  bool resume=false);
 
    bool Cancel();
    virtual void Release();
 
  private:
    TWaitableTimer(const TWaitableTimer&);
    const TWaitableTimer& operator =(const TWaitableTimer&);
};
 
 
//
/// \class TSemaphoreSet
// ~~~~~ ~~~~~~~~~~~~~
/// Semaphore object aggregator. Used to combine a set of semaphore objects so
/// that they can be waited upon (locked) as a group. The lock can wait for any
/// one, or all of them. The semaphore objects to be aggregated MUST live at
/// least as long as this TSemaphoreSet, as it maintains pointers to them.
//
class _OWLCLASS TSemaphoreSet{
  public:
    /// sems is initial array of sem ptrs, may be 0 to add sems later,
    /// size is maximum sems to hold, -1 means count the 0-terminated array
    /// Passing (0,-1) is not valid
    //
    TSemaphoreSet(const TSemaphore* sems[], int size = -1);
   ~TSemaphoreSet();
 
    void Add(const TSemaphore& sem);
    void Remove(const TSemaphore& sem);
    int  GetCount() const;
    const TSemaphore* operator [](int index) const;
 
    enum TWaitWhat { WaitAny = false, WaitAll = true };
    enum { NoWait = 0, NoLimit = INFINITE };
 
    class _OWLCLASS TLock {
      public:
        /// Assumes that set is not modified while locked
        //
        TLock(const TSemaphoreSet& set, TWaitWhat wait,
              ulong timeOut = NoLimit, bool alertable = false);
        TLock(ulong msgMask, const TSemaphoreSet& set, TWaitWhat wait,
              ulong timeOut = NoLimit);
       ~TLock();
 
        bool WasAquired() const;    ///< See if one or more was aquired
        enum {
          AllAquired = -1,   ///< All semaphores were aquired
          TimedOut   = -2,   ///< None aquired: timed out
          IoComplete = -3,   ///<               IO complate alert
          MsgWaiting = -4,   ///<               Msg waiting
        };
        int  WhichAquired() const;  ///< See which was aquired >=0, or enum
 
        void Release(bool relinquish = false);
 
      protected:
        bool InitLock(int count, TWaitWhat wait, int index);
 
      private:
        const TSemaphoreSet* Set;
        int   Locked;    ///< Which one got locked, or wait code
    };
    friend class TLock;
 
  private:
    void Release(int index = -1);
 
    typedef TSemaphore* TSemaphorePtr;
    typedef HANDLE THandle;
 
    const TSemaphore** Sems;    ///< Array of ptrs to semaphores, packed at head
 
    int   Size;   ///< Size of array, i.e. maximum object count
    int   Count;  ///< Count of objects currently in array
};
 
//
/// \class TCriticalSection
// ~~~~~ ~~~~~~~~~~~~~~~~
/// Lightweight intra-process thread synchronization. Can only be used with
/// other critical sections, and only within the same process.
//
/// TCriticalSection provides a system-independent interface to critical sections in
/// threads. TCriticalSection objects can be used in conjunction with
/// TCriticalSection::Lock objects to guarantee that only one thread can be
/// executing any of the code sections protected by the lock at any given time.
//
class TCriticalSection{
  public:
    TCriticalSection();
   ~TCriticalSection();
 
/// This nested class handles locking and unlocking critical sections.
///
/// Only one thread of execution will be allowed to execute the critical code inside
/// function f at any one time.
/// \code
/// TCriticalSection LockF;
/// void f()
/// {
///    TCriticalSection::Lock(LockF);
///
///    // critical processing here
/// }
/// \endcode
    class TLock {
      public:
        TLock(const TCriticalSection&);
       ~TLock();
      private:
        const TCriticalSection& CritSecObj;
    };
    friend class TLock;
    typedef TLock Lock;  ///< For compatibility with old T-less typename
 
  private:
    CRITICAL_SECTION CritSec;
 
    TCriticalSection(const TCriticalSection&);
    const TCriticalSection& operator =(const TCriticalSection&);
};
 
//
/// \class TMRSWSection
/// Multiple Read, Single Write section
//
class _OWLCLASS TMRSWSection
{
public:
 
  TMRSWSection();
  ~TMRSWSection();
 
  class _OWLCLASS TLock
  {
  public:
 
    //
    /// shared == true; allows multiple (read) access to the section.
    /// shared == false; allows only exclusive (write) access to the section.
    /// wait == false; will throw an exception if the lock can not be acquired immediately.
    ///
    /// TXLockFailure is thrown on failure.
    //
    TLock(TMRSWSection&, bool shared, bool wait = true);
    ~TLock();
 
  private:
 
    TMRSWSection& Section;
 
    TLock(const TLock&); ///< prohibited
    const TLock& operator =(const TLock&); ///< prohibited
  };
 
  friend class TMRSWSection::TLock;
 
  class _OWLCLASS TXLockFailure
    : public TXBase
  {
  public:
 
    explicit TXLockFailure(const tstring& msg);
  };
 
  //
  /// Dumps the current state of the section to the debugger output.
  //
  void Dump();
 
private:
 
  struct TPimpl;
  TPimpl* Pimpl;
 
  TMRSWSection(const TMRSWSection&); ///< prohibited
  const TMRSWSection& operator =(const TMRSWSection&); ///< prohibited
};
 
//
// class TSync::TLock
// ~~~~~ ~~~~~~~~~~~
/// \class TSync
/// 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.
///
/// Example
/// \code
///     class ThreadSafe : private TSync
///     {
///       public:
///         void f();
///         void g();
///       private:
///         int i;
///     };
///
///     void ThreadSafe::f()
///     {
///       TLock lock(this);
///       if (i == 2)
///         i = 3;
///     }
///
///     void ThreadSafe::g()
///     {
///       TLock lock(this);
///       if (i == 3)
///         i = 2;
///     }
/// \endcode
//
class TSync
{
  protected:
    TSync();
    TSync(const TSync&);
    const TSync& operator =(const TSync&);
 
/// This nested class handles locking and unlocking critical sections.
    class TLock : private TCriticalSection::TLock
    {
      public:
        TLock(const TSync*);
      private:
        static const TCriticalSection& GetRef(const TSync*);
    };
    friend class TLock;
    typedef TLock Lock;  ///< For compatibility with old T-less typename
 
  private:
    TCriticalSection CritSec;
};
 
//
/// \class TStaticSync
// template <class T> class TStaticSync
// template <class T> class TStaticSync::TLock
// ~~~~~~~~ ~~~~~~~~~ ~~~~~ ~~~~~~~~~~~~~~~~~
/// 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 TLock;            Handles locking and unlocking of member
//                             functions.
//
/// Example
// ~~~~~~~
/// \code
///     class ThreadSafe : private TStaticSync<ThreadSafe>
///     {
///       public:
///         void f();
///         void g();
///       private:
///         static int i;
///     };
///
///     void ThreadSafe::f()
///     {
///       TLock lock;
///       if (i == 2)
///         i = 3;
///     }
///
///     void ThreadSafe::g()
///     {
///       TLock lock;
///       if (i == 3)
///         i = 2;
///     }
/// \endcode
//
template <class T> class TStaticSync{
  protected:
    TStaticSync();
    TStaticSync(const TStaticSync<T>&);
    const TStaticSync<T>& operator =(const TStaticSync<T>&);
   ~TStaticSync();
 
    class TLock : private TCriticalSection::TLock
    {
      public:
        TLock() : TCriticalSection::TLock(*TStaticSync<T>::CritSec) {}
    };
    friend class TLock;
    typedef TLock Lock;  ///< For compatibility with old T-less typename
 
  private:
    static TCriticalSection* CritSec;
    static ulong Count;
};
 
//
/// \class TThread
// ~~~~~ ~~~~~~~
/// TThread provides a system-independent interface to threads. With
/// suitable underlying implementations the same code can be used under
/// OS/2 and Win32.
///
/// Example
/// \code
///     class TimerThread : public TThread
///     {
///       public:
///         TimerThread() : Count(0) {}
///       private:
///         int Run();
///         int Count;
///     };
///
///     int TimerThread::Run()
///     {
///       // loop 10 times
///       while (Count++ < 10) {
///         Sleep(1000);    // delay 1 second
///         cout << "Iteration " << Count << endl;
///       }
///       return 0;
///     }
///
///     int main()
///     {
///       TimerThread timer;
///       timer.Start();
///       Sleep(20000);     // delay 20 seconds
///       return 0;
///     }
/// \endcode
///
/// 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 _OWLCLASS TThread
{
  public:
    enum { NoLimit = INFINITE };
    typedef HANDLE THandle;
 
    // Attach to the current running (often primary) thread
    //
    enum TCurrent {Current};
    TThread(TCurrent);
 
    /// Identifies the states that the class can be in.
    enum TStatus
    {
      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.
    };
 
    THandle Start();
    ulong   Suspend();
    ulong   Resume();
    bool    Sleep(long timeMS, bool alertable = false);
 
    virtual void    Terminate();
    ulong   WaitForExit(ulong timeout = NoLimit);
    ulong   TerminateAndWait(ulong timeout = NoLimit);
 
    TStatus GetStatus() const;
    uint32  GetExitCode() const;
 
    enum TPriority {
      Idle         = THREAD_PRIORITY_IDLE,          ///< -15
      Lowest       = THREAD_PRIORITY_LOWEST,        ///<  -2
      BelowNormal  = THREAD_PRIORITY_BELOW_NORMAL,  ///<  -1
      Normal       = THREAD_PRIORITY_NORMAL,        ///<   0
      AboveNormal  = THREAD_PRIORITY_ABOVE_NORMAL,  ///<   1
      Highest      = THREAD_PRIORITY_HIGHEST,       ///<   2
      TimeCritical = THREAD_PRIORITY_TIME_CRITICAL, ///<  15
    };
 
    int GetPriority() const;
    int SetPriority(int);   ///< Can pass a TPriority for simplicity
 
    /// The error class that defines the objects that are thrown when an error occurs.
    class TThreadError : public TXBase  {
      public:
        /// Identifies the type of error that occurred.
        enum TErrorType {
          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.
          NoMTRuntime,        ///< This usually results when you attempt to execute a multithread
                              ///< application which includes a module that has not been properly
                              ///< compiled with the appropriate multithread options.
 
        };
        typedef TErrorType ErrorType;
        TErrorType GetErrorType() const;
 
      private:
        TThreadError(TErrorType type);
        static tstring MakeString(ErrorType type);
        TErrorType Type;
      friend class _OWLCLASS TThread;
    };
 
    typedef TStatus Status;     ///< For compatibility with old T-less typenames
    typedef TThreadError ThreadError;
 
  protected:
    TThread();          ///< Create a thread. Derived class overrides Run()
 
    // Copying a thread puts the target into the Created state
    //
    TThread(const TThread&);
    const TThread& operator =(const TThread&);
 
    virtual ~TThread();
 
    bool    ShouldTerminate() const;
    void    Exit(ulong code);  ///< Alternative to returning from Run()
 
  private:
    virtual int Run();
 
    TStatus CheckStatus() const;
 
#if defined(BI_MULTI_THREAD_RTL)
    static uint __stdcall Execute(void* thread);
#else
    static DWORD WINAPI Execute(void* thread);
#endif
 
    DWORD ThreadId;
    THandle Handle;
    mutable TStatus Stat;
    bool TerminationRequested;
    bool Attached;
};
 
#if defined(BI_MULTI_THREAD_RTL)
 
//
/// All classes used in local/tls process data have to be derived from here.
//
class TLocalObject : public TStandardAllocator {
  public:
    TLocalObject(){}
    virtual ~TLocalObject(){}
};
 
//
/// Exception class for TTlsContainer
//
class TXTlsContainer : public TXBase
{
public:
 
  TXTlsContainer(const tstring& msg)
    : TXBase(msg)
  {}
};
 
//
/// Thread-local storage container
/// Wraps a used-defined type, and provides separate instances of this type to each client thread.
/// The wrapped type must be default-constructible.
///
/// This class is normally used as a singleton.
/// Note that the construction of a singleton of this class must be synchronized (serialized execution).
/// A simple way to ensure this is to initialize it at program startup (single-threaded execution).
///
/// Usage:
///
/// \code
/// TFoo& GetFoo() // Meyers Singleton ensures global-initialization-order independency.
/// {
///   static TTlsContainer<TFoo> c;
///   return c.GetData(); // OWL5_COMPAT: return c; // implicit conversion
/// }
///
/// TFoo& init = GetFoo(); // Ensures initialization during start-up (i.e. single-threaded and safe).
/// \endcode
//
template <class T>
class TTlsContainer
{
public:
 
  TTlsContainer()
    : Index(::TlsAlloc())
  {
    TRACEX(OwlThread, 1, "Initializing " << TraceId(this));
    if (Index == TLS_OUT_OF_INDEXES)
      throw TXTlsContainer(_T("TLS_OUT_OF_INDEXES"));
  }
 
  //
  /// Deallocates all the thread-level data created by the container.
  //
  ~TTlsContainer()
  {
    TRACEX(OwlThread, 1, "Destructing " << TraceId(this));
    ::TlsFree(Index);
    TCriticalSection::TLock lock(GarbageSection);
    std::for_each(Garbage.begin(), Garbage.end(), &Delete);
  }
 
  //
  /// Returns 0 if data for the calling thread has not yet been allocated,
  /// otherwise a pointer to previously initialized data is returned.
  /// If the function returns 0, you can call Get to create an instance.
  /// Can safely be called by many threads simultaneously without synchronization.
  //
  T* Query()
  {return static_cast<T*>(::TlsGetValue(Index));}
 
  //
  /// Returns the thread-local instance of the data.
  /// Can safely be called by many threads simultaneously without synchronization.
  //
  T& Get()
  {
    T* p = Query();
    return p ? *p : Create();
  }
 
  //
  /// Const overload
  //
  const T* Query() const
  {return const_cast<TTlsContainer*>(this)->Query();}
 
  //
  /// Const overload
  //
  const T& Get() const
  {return const_cast<TTlsContainer*>(this)->Get();}
 
  // Old interface for backwards compatibility:
 
#if defined(OWL5_COMPAT)
 
  T* QueryData()
  {return Query();}
 
  T* GetData()
  {return &Get();}
 
  operator T*()
  {return &Get();}
 
  operator T&()
  {return Get();}
 
  T* operator->()
  {return &Get();}
 
#endif
 
protected:
 
  const DWORD Index;
  TCriticalSection GarbageSection;
  std::vector<T*> Garbage;
 
  T& Create()
  {
    T* p = new T(); CHECK(p);
    bool r = ::TlsSetValue(Index, p); CHECK(r); InUse(r);
    TRACEX(OwlThread, 1, TraceId(this) << " created " << TraceId(p) << " for thread " << GetCurrentThreadId());
 
    // Store the pointer for garbage collection later.
    //
    TCriticalSection::TLock lock(GarbageSection);
    Garbage.push_back(p);
    return *p;
  }
 
  static void Delete(T* p)
  {
    delete p;
    TRACEX(OwlThread, 1, TraceType<TTlsContainer>() << " deleted " << TraceId(p));
  }
 
private:
 
  TTlsContainer(const TTlsContainer&); // prohibit
  TTlsContainer& operator =(const TTlsContainer&); // prohibit
 
};
 
//
// The following TLS support classes are only available in OWL 5 compatibility mode.
//
 
#if defined(OWL5_COMPAT)
 
//
// Created by Yura Bidus
// Multithread OWL internal support
//
 
class TLocalData: public TLocalObject {
  typedef TMIPtrArray<TLocalObject*,TLocalObject*,TLocalObject>  TLocalObjectArray;
  public:
    TLocalData(){}
    virtual ~TLocalData(){}
 
    TLocalObject* GetData(int index)
      {
        return index < (int)Data.Size() ? Data[index] : 0;
      }
 
    void SetData(int index, TLocalObject* obj);
 
    int  AddData(TLocalObject* data) { return Data.Add(data); }
 
  protected:
    TLocalObjectArray Data;
};
 
class TTlsAllocator {
  public:
    TTlsAllocator()              { index = ::TlsAlloc();}
    ~TTlsAllocator()            { ::TlsFree(index);    }
 
    bool  IsOk()                { return index != 0xFFFFFFFF; }
    bool  SetValue(void* value)  { return ::TlsSetValue(index, value); }
    void* GetValue()            { return ::TlsGetValue(index);        }
 
  private:
    uint32 index;
};
 
class TTlsDataManager : public TLocalObject {
  typedef TMIPtrArray<TLocalData*,TLocalData*,TLocalObject>  TLocalDataArray;
  public:
    TTlsDataManager()
      {
        CHECK(Allocator.IsOk());
      }
    virtual ~TTlsDataManager()
      {
        TMRSWSection::TLock __lock(Lock,false,true);
        Data.Flush(true);
      }
 
    TLocalObject* GetData(int index)
      {
        TLocalData* data = (TLocalData*)Allocator.GetValue();
        return (data ? data : CreateData())->GetData(index);
      }
    void SetData(int index, TLocalObject* obj)
      {
        TLocalData* data = (TLocalData*)Allocator.GetValue();
        (data ? data : CreateData())->SetData(index, obj);
      }
    int AddData(TLocalObject* obj)
      {
        TLocalData* data = (TLocalData*)Allocator.GetValue();
        return (data ? data : CreateData())->AddData(obj);
      }
  protected:
    TLocalData* CreateData()
      {
        TMRSWSection::TLock __lock(Lock,false,true);
        TLocalData* data = new TLocalData();
        Data.Add(data);
        Allocator.SetValue(data);
        return data;
      }
 
  protected: // global static data
    TTlsAllocator    Allocator;
    TLocalDataArray  Data;
    TMRSWSection    Lock;
};
 
template <class T> class TProcessContainer: public TLocalObject{
  public:
    TProcessContainer():Object(0){}
    virtual ~TProcessContainer(){ delete Object;}
 
    inline T* GetData()
      {
        if(!Object) // throw bad_alloc if error ??
          Object = new T;
        // check that T derived from TLocalObject
        CHECK(dynamic_cast<TLocalObject*>(Object));
        return Object;
      }
    inline T* QueryData()  {  return Object;    }
    inline operator T*()  { return GetData(); }
    inline operator T&()  { return *GetData();}
    inline T* operator->(){ return GetData(); }
 
  protected:
    T* Object;
};
 
#endif
 
#endif
 
/// @}
 
/// \cond NoSuppressDoxygenWarning
#include <owl/posclass.h>
/// \endcond
 
//----------------------------------------------------------------------------
// Inline implementation
//
 
 
//----------------------------------------
// TSemaphore Win32
 
//
inline TSemaphore::~TSemaphore()
{
  ::CloseHandle(Handle);
}
 
//
inline TSemaphore::operator TSemaphore::THandle() const
{
  return Handle;
}
 
//
inline TSemaphore::TLock::TLock(const TSemaphore& sem, ulong timeOut, bool alertable)
:
  Sem(0)
{
  if (::WaitForSingleObjectEx(sem, timeOut, alertable) == 0)
    Sem = &sem;
}
 
//
inline TSemaphore::TLock::~TLock()
{
  Release();
}
 
//
inline bool TSemaphore::TLock::WasAquired() const
{
  return Sem != 0;
}
 
//
// Release but hang on to the semaphore
//
inline void TSemaphore::TLock::Release(bool relinquish)
{
  if (Sem) {
    CONST_CAST(TSemaphore*,Sem)->Release();
    if (relinquish)
      Sem = 0;
  }
}
 
//----------------------------------------
// TMutex Win32
 
//
 
/// Constructs a TMutex instance encapsulating a newly created named or unnamed
/// mutex object. The name parameter points to a null-terminated string specifying
/// the name of the mutex object. The sa parameter points to a SECURITY_ATTRIBUTES
/// structure that specifies the security attributes of the mutex object.
/// \note The mutex object is not owned.
inline TMutex::TMutex(LPCTSTR name, LPSECURITY_ATTRIBUTES sa)
 : Shared(false)
{
  Handle = ::CreateMutex(sa, false, name);  // don't aquire now
  if (Handle && (GetLastError() == ERROR_ALREADY_EXISTS))
    Shared = true;
}
 
//
/// String-aware overload
//
inline TMutex::TMutex(const tstring& name, LPSECURITY_ATTRIBUTES sa)
 : Shared(false)
{
  Handle = ::CreateMutex(sa, false, name.c_str());  // don't aquire now
  if (Handle && (GetLastError() == ERROR_ALREADY_EXISTS))
    Shared = true;
}
 
//
/// Open an existing mutex. Fails if not there.
//
/// This form of the constructor instantiates a TMutex object that encapsulates an
/// existing named mutex object. The name parameter points to a null-terminated
/// string that names the mutex to be opened.
inline TMutex::TMutex(LPCTSTR name, bool inherit, uint32 access)
  : Shared(false)
{
  Handle = ::OpenMutex(access, inherit, name);
  if (Handle)
    Shared = true;
}
 
//
/// String-aware overlaod
//
inline TMutex::TMutex(const tstring& name, bool inherit, uint32 access)
  : Shared(false)
{
  Handle = ::OpenMutex(access, inherit, name.c_str());
  if (Handle)
    Shared = true;
}
 
//
/// Constructs a Tmutex instance encapsulating a handle obtained by duplicating the
/// specified handle. The handle parameter is the source mutex object to be
/// duplicated.
/// \note The duplicated handle has the same access attributes as the source handle.
//
inline TMutex::TMutex(THandle handle)
  : Shared(false)
{
  if (::DuplicateHandle(::GetCurrentProcess(), handle,
                        ::GetCurrentProcess(), &Handle,
                        0, false, DUPLICATE_SAME_ACCESS))
  {
    Shared = true;
  }
}
 
//
//
//
inline bool TMutex::IsShared()
{
  return Shared;
}
 
//----------------------------------------
// TCountedSemaphore Win32
 
//
inline TCountedSemaphore::TCountedSemaphore(int initialCount, int maxCount,
                                            LPCTSTR name,
                                            LPSECURITY_ATTRIBUTES sa)
{
  Handle = ::CreateSemaphore(sa, initialCount, maxCount, name);
}
 
//
// String-aware overload
//
inline TCountedSemaphore::TCountedSemaphore(int initialCount, int maxCount, const tstring& name, LPSECURITY_ATTRIBUTES sa)
{
  Handle = ::CreateSemaphore(sa, initialCount, maxCount, name.c_str());
}
 
//
inline TCountedSemaphore::TCountedSemaphore(LPCTSTR name, bool inherit,
                                            uint32 access)
{
  Handle = ::OpenSemaphore(access, inherit, name);
}
 
//
// String-aware overload
//
inline TCountedSemaphore::TCountedSemaphore(const tstring& name, bool inherit, uint32 access)
{
  Handle = ::OpenSemaphore(access, inherit, name.c_str());
}
 
//
inline TCountedSemaphore::TCountedSemaphore(THandle handle)
{
  ::DuplicateHandle(::GetCurrentProcess(), handle,
                    ::GetCurrentProcess(), &Handle,
                    0, false, DUPLICATE_SAME_ACCESS);
}
 
//----------------------------------------
// TEventSemaphore Win32
 
inline TEventSemaphore::TEventSemaphore(bool manualReset, bool initialState,
                                        LPCTSTR name,
                                        LPSECURITY_ATTRIBUTES sa)
{
  Handle = ::CreateEvent(sa, manualReset, initialState, name);
}
 
//
// String-aware overload
//
inline TEventSemaphore::TEventSemaphore(bool manualReset, bool initialState, const tstring& name, LPSECURITY_ATTRIBUTES sa)
{
  Handle = ::CreateEvent(sa, manualReset, initialState, name.c_str());
}
 
//
inline TEventSemaphore::TEventSemaphore(LPCTSTR name, bool inherit,
                                        uint32 access)
{
  Handle = ::OpenEvent(access, inherit, name);
}
 
//
// String-aware overload
//
inline TEventSemaphore::TEventSemaphore(const tstring& name, bool inherit, uint32 access)
{
  Handle = ::OpenEvent(access, inherit, name.c_str());
}
 
//
inline TEventSemaphore::TEventSemaphore(THandle handle)
{
  ::DuplicateHandle(::GetCurrentProcess(), handle,
                    ::GetCurrentProcess(), &Handle,
                    0, false, DUPLICATE_SAME_ACCESS);
}
 
inline void TEventSemaphore::Set()
{
  ::SetEvent(*this);
}
 
inline void TEventSemaphore::Reset()
{
  ::ResetEvent(*this);
}
 
inline void TEventSemaphore::Pulse()
{
  ::PulseEvent(*this);
}
 
//----------------------------------------
// TWaitableTimer Win NT or Win98
inline TWaitableTimer::TWaitableTimer(THandle handle)
{
  ::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(),
                    &Handle, 0, false, DUPLICATE_SAME_ACCESS);
}
 
inline  TWaitableTimer::~TWaitableTimer()
{
  ::CloseHandle(Handle);
}
//----------------------------------------
// TSemaphoreSet Win32
 
inline int TSemaphoreSet::GetCount() const
{
  return Count;
}
 
inline const TSemaphore* TSemaphoreSet::operator [](int index) const
{
  return (index >= 0 && index < Count) ? Sems[index] : 0;
}
 
//
inline bool TSemaphoreSet::TLock::WasAquired() const
{
  return Set != 0;
}
 
//
/// Which one was locked, all locked code, or lock fail code
//
inline int TSemaphoreSet::TLock::WhichAquired() const
{
  return Locked;
}
 
 
//----------------------------------------------------------------------------
// TCriticalSection Win32
//
 
//
/// Use system call to initialize the CRITICAL_SECTION object.
//
inline TCriticalSection::TCriticalSection()
{
  ::InitializeCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSec));
}
 
//
/// Use system call to destroy the CRITICAL_SECTION object.
//
inline TCriticalSection::~TCriticalSection()
{
  ::DeleteCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSec));
}
 
//
/// Use system call to lock the CRITICAL_SECTION object.
//
/// Requests a lock on the TCriticalSection object. If no other Lock object holds a
/// lock on that TCriticalSection object, the lock is allowed and execution
/// continues. If another Lock object holds a lock on that object, the requesting
/// thread is blocked until the lock is released.
//
inline TCriticalSection::TLock::TLock(const TCriticalSection& sec)
:
  CritSecObj(sec)
{
  ::EnterCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSecObj.CritSec));
}
 
//
/// Use system call to unlock the CRITICAL_SECTION object.
//
inline TCriticalSection::TLock::~TLock()
{
  ::LeaveCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSecObj.CritSec));
}
 
//
// TCriticalSection OS2
//
 
 
//----------------------------------------------------------------------------
 
//
/// Default constructor.
inline TSync::TSync()
{
}
 
//
/// 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(const TSync&)
{
}
 
//
/// 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;
}
 
//
/// Locks the TCriticalSection object in the TSync object.
//
/// Requests a lock on the critical section of the TSync object pointed to by s. If
/// no other Lock object holds a lock on that TCriticalSection object, the lock is
/// allowed and execution continues. If another Lock object holds a lock on that
/// object, the requesting thread is blocked until the lock is released.
inline TSync::TLock::TLock(const TSync* sync)
:
  TCriticalSection::TLock(GetRef(sync))
{
}
 
//
// 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::TLock::GetRef(const TSync* sync)
{
  CHECK(sync != 0);
  return sync->CritSec;
}
 
//----------------------------------------------------------------------------
 
//
// Instantiate the data members.
//
template <class T> TCriticalSection* TStaticSync<T>::CritSec;
template <class T> ulong TStaticSync<T>::Count;
 
//
// 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;
}
 
//
// If this is the only remaining TStaticSync<T> object, destroy the semaphore.
//
template <class T> inline TStaticSync<T>::~TStaticSync()
{
  if (--Count == 0)
    delete CritSec;
}
 
//----------------------------------------------------------------------------
 
//
/// Suspends execution of the current thread for the number of milliseconds
/// specified by the timeMS parameter. If the alertable parameter is set to true,
/// the function resumes execution upon I/O completion.
///
/// The function returns true if its wakeup is due to I/O completion.
//
inline bool TThread::Sleep(long timeMS, bool alertable)
{
  return ::SleepEx(timeMS, alertable) == WAIT_IO_COMPLETION;
}
 
//
/// Gets the current status of the thread.
//
/// If the thread is marked as Running it may have terminated without our
/// knowing it, so we have to check.
//
inline TThread::TStatus TThread::GetStatus() const
{
  if (Stat == Running)
    Stat = CheckStatus();
  return Stat;
}
 
//
inline uint32  TThread::GetExitCode() const
{
  uint32 code;
  ::GetExitCodeThread(Handle, (DWORD*)&code);
  return code;
}
 
//
/// Gets the thread priority. Under Win32, this is a direct call to the operating
/// system. See the description of TPriority for possible values.
//
inline int TThread::GetPriority() const
{
  return ::GetThreadPriority(Handle);
}
 
//
/// Returns a bool 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.
//
inline bool TThread::ShouldTerminate() const
{
  return TerminationRequested;
}
 
/// Returns a code indicating the type of error that occurred.
inline TThread::TThreadError::TErrorType TThread::TThreadError::GetErrorType() const
{
  return Type;
}
 
} // OWL namespace
 
#endif  // OWL_THREAD_H

V302 Member operator[] of 'TSemaphoreSet' class has a 32-bit type argument. Use memsize-type here.

V1004 The 'sync' pointer was used unsafely after it was verified against nullptr. Check lines: 1348, 1349.

V832 It's better to use '= default;' syntax instead of empty constructor body.