    //------------------------------------------------------------------------------
    // emThread.h
    //
    // Copyright (C) 2009-2010,2016-2017 Oliver Hamann.
    //
    // Homepage: http://eaglemode.sourceforge.net/
    //
    // This program is free software: you can redistribute it and/or modify it under
    // the terms of the GNU General Public License version 3 as published by the
    // Free Software Foundation.
    //
    // This program is distributed in the hope that it will be useful, but WITHOUT
    // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
    // more details.
    //
    // You should have received a copy of the GNU General Public License version 3
    // along with this program. If not, see <http://www.gnu.org/licenses/>.
    //------------------------------------------------------------------------------

    #ifndef emThread_h
    #define emThread_h

    #ifndef emStd2_h
    #include <emCore/emStd2.h>
    #endif

    class emThreadPrivate;
    struct emThreadEventReceiver;

    //==============================================================================
    //================================= emThreadId =================================
    //==============================================================================

    typedef emUInt64 emThreadId;

    //==============================================================================
    //================================== emThread ==================================
    //==============================================================================

    class emThread : public emUncopyable {

    public:

            // Class for a thread of program execution.
            //
            // Some hints on multi-threading:
            // - Where not stated otherwise, all classes and functions of emCore are
            //   thread-reentrant but not thread-safe. This means that the classes
            //   and functions can be used by multiple threads simultaneously only
            //   if no shared data is accessed. Yes, even emContext is not
            //   thread-safe.
            // - The objects of container classes like emString, emArray, emList and
            //   emImage are sharing data implicitly. You cannot protect that data
            //   with a mutex. Instead, these classes have a method named
            //   MakeNonShared which must always be called before giving the object
            //   to another thread.
            // - Multi-threading provides many pitfalls, and the correctness of
            //   multi-threaded programs cannot be proved by testing very well.
            // - Alternative concepts are: emEngine, emProcess.

            emThread();
                    // Construct a thread object where the thread is not yet
                    // running.

            virtual ~emThread();
                    // If the thread is still running, WaitForTermination() is
                    // called.

            void Start(void * arg);
                    // This is a short cut for Start(NULL,arg). Should only be used
                    // if Run has been overloaded.

            void Start(int (* func)(void *), void * arg);
                    // Start this thread. The thread calls the method Run, and the
                    // default Implementation of that method calls the function
                    // func. arg is a custom pointer forwarded to Run and func.

            static void StartUnmanaged(int (* func)(void *), void * arg);
                    // This function is like the method Start, but the new thread is
                    // not managed by an emThread object and the function func is
                    // called directly instead of Run. Yes, the return value of func
                    // has no meaning and exists only for compatibility with managed
                    // threads.

            bool WaitForTermination(unsigned timeoutMS=UINT_MAX);
                    // Wait for the thread to terminate.
                    // Arguments:
                    //   timeoutMS - Time-out in milliseconds. UINT_MAX means
                    //               infinite.
                    // Returns:
                    //   true if the thread has terminated (or never started), or
                    //   false on time-out.

            bool IsRunning();
                    // Whether the thread has been started and not yet exited.

            int GetExitStatus() const;
                    // Get the return value of a terminated thread.

            emThreadId GetThreadId() const;
                    // Get the identity number of this thread, if running.

            static emThreadId GetCurrentThreadId();
                    // Get the identity number of the calling thread.

            static void ExitCurrentThread(int exitStatus);
                    // Exit the calling thread.

            static int GetHardwareThreadCount();
                    // Maximum number of threads the hardware can run concurrently.

    protected:

            virtual int Run(void * arg);
                    // The default implementation calls the function given with the
                    // Start method.

    private:

            friend class emThreadPrivate;
            emThreadPrivate * P;
    };

    inline void emThread::Start(void * arg)
    {
            Start(NULL,arg);
    }

    inline bool emThread::IsRunning()
    {
            return !WaitForTermination(0);
    }

    //==============================================================================
    //============================ emThreadMutexLocker =============================
    //==============================================================================

    template <class OBJ> class emThreadMutexLocker : public emUncopyable {

    public:

            // This is a template class for a locker which simply locks a mutex for
            // the time the locker exists. The template parameter OBJ describes the
            // class of the mutex.

            emThreadMutexLocker(OBJ & mutex);
                    // Calls Lock() on the given mutex.
                    // Arguments:
                    //   mutex - The mutex to be locked by this locker.

            ~emThreadMutexLocker();
                    // Calls Unlock() on the mutex.

            OBJ & GetMutex() const;
                    // Get the mutex which is locked by this locker.

    private:

            OBJ & Mutex;
    };

    template <class OBJ> inline emThreadMutexLocker<OBJ>::emThreadMutexLocker(
            OBJ & mutex
    )
            : Mutex(mutex)
    {
            Mutex.Lock();
    }

    template <class OBJ> inline emThreadMutexLocker<OBJ>::~emThreadMutexLocker()
    {
            Mutex.Unlock();
    }

    template <class OBJ> inline OBJ & emThreadMutexLocker<OBJ>::GetMutex() const
    {
            return Mutex;
    }

    //==============================================================================
    //============================= emThreadMiniMutex ==============================
    //==============================================================================

    class emThreadMiniMutex : public emUncopyable {

    public:

            // Class for a mutual exclusion variable with minimum costs. It could
            // also be called a "spin lock". This type of mutex may perform some
            // kind of busy waiting, and it may be unfair. Therefore it should be
            // used for very short critical sections only, so that it is very
            // unlikely that a thread really has to wait. This mutex also does not
            // support recursive locks.

            emThreadMiniMutex();
            ~emThreadMiniMutex();

            void Lock();
                    // Lock this mutex. Only one thread can have the mutex locked at
                    // a time. Therefore this method may block in order to wait for
                    // unlocked state. It may be a kind of busy waiting (yielding to
                    // another thread again and again).

            void Unlock();
                    // Unlock this mutex.

            typedef emThreadMutexLocker<emThreadMiniMutex> Locker;
                    // A locker class for this mutex class.

    private:

            union {
                    emInt64 Val;
                    void * Ptr;
            };
    };

    //==============================================================================
    //=============================== emThreadEvent ================================
    //==============================================================================

    class emThreadEvent : public emUncopyable {

    public:

            // Class for an unary event that can be used for thread communication.
            // It is much like a classic semaphore, but the methods are named "Send"
            // and "Receive" instead of "Increment" and "Decrement".

            emThreadEvent();
                    // Construct with no pending events.

            emThreadEvent(int count);
                    // Construct with an initial number of pending event, or, if
                    // count is negative, with an initial phantom receiver. See
                    // SetCount.

            ~emThreadEvent();
                    // Destructor.

            emInt64 Send(emInt64 n=1);
                    // Send this event n times. If one or more threads are blocked
                    // in Receive, they are served accordingly. A negative n means
                    // to decrease the internal counter of pending events (which can
                    // be negative) - it acts like a phantom receiver which has
                    // precedence over all the other receivers.
                    // Arguments:
                    //   n         - How many events to send. A negative n acts like
                    //               a phantom receiver.
                    // Returns:
                    //   Same as GetCount.

            bool Receive(emInt64 n=1, unsigned timeoutMS=UINT_MAX);
                    // Receive this event n times. If there are at least n pending
                    // events, this method returns immediately. Otherwise this
                    // thread is added to an internal queue and it sleeps until it
                    // is removed from the queue by Send, or until the time-out
                    // elapses.
                    // Arguments:
                    //   n         - How many events to receive. A negative n acts
                    //               exactly like Send(-n).
                    //   timeoutMS - Time-out in milliseconds. UINT_MAX means
                    //               infinite.
                    // Returns:
                    //   true if the events have been received, or false on
                    //   time-out. On time-out, absolute no event is removed from
                    //   the internal counter.

            emInt64 GetCount() const;
                    // Get the number of pending sendings of this event. A negative
                    // value indicates waiting receivers.

            void SetCount(emInt64 count);
                    // Same as Send(count-GetCount()), but atomically.

            void Clear();
                    // Same as SetCount(0).

    private:

            void UpdateReceivers();

            emThreadMiniMutex Mutex;
            emInt64 Count;
            emThreadEventReceiver * Ring;
    };

    inline void emThreadEvent::Clear()
    {
            SetCount(0);
    }

    //==============================================================================
    //=============================== emThreadMutex ================================
    //==============================================================================

    class emThreadMutex : private emUncopyable {

    public:

            // Class for a normal mutual exclusion variable. Its properties are:
            // - The lock methods support a time-out.
            // - Waiting is non-busy.
            // - Waiting is fair (first come, first serve).
            // - There are methods for solving the readers/writers problem. This
            //   means, the mutex can be locked by either a single thread for
            //   read/write access, or by one or more threads for read-only
            //   access. If you don't need that, simply don't use the *ReadOnly
            //   methods.
            // - This mutex does not support recursive locks. A thread would
            //   dead-lock when trying to lock the mutex more than once (except when
            //   locking for read-only access).

            emThreadMutex();
            ~emThreadMutex();

            bool Lock(unsigned timeoutMS=UINT_MAX);
                    // Lock this mutex (for read/write access). Only one thread can
                    // have the mutex locked this way at a time, without any
                    // read-access locks in parallel. Therefore this method may
                    // block in order to wait for unlocked state.
                    // Arguments:
                    //   timeoutMS - Time-out in milliseconds. UINT_MAX means
                    //               infinite.
                    // Returns:
                    //   true if the mutex has been locked, false on time-out.

            void Unlock();
                    // Unlock this mutex (from read/write access).

            bool IsLocked() const;
                    // Whether this mutex is currently locked (for read/write
                    // access).

            bool LockReadOnly(unsigned timeoutMS=UINT_MAX);
                    // Lock this mutex for read-only access. Multiple threads
                    // can have locked the mutex this way simultaneously. If a
                    // thread has locked the mutex for read/write access (with
                    // Lock), this method may block in order to wait for unlocked
                    // state.
                    // Arguments:
                    //   timeoutMS - Time-out in milliseconds. UINT_MAX means
                    //               infinite.
                    // Returns:
                    //   true if the mutex has been locked, false on time-out.

            void UnlockReadOnly();
                    // Unlock this mutex from read/write access.

            bool IsLockedAnyhow() const;
                    // Whether this mutex is currently locked for any access.

            typedef emThreadMutexLocker<emThreadMutex> Locker;
                    // A locker class for this mutex class.

            class ReadOnlyLocker : public emUncopyable {
            public:
                    // A read-only locker class for this mutex class.
                    ReadOnlyLocker(emThreadMutex & mutex);
                    ~ReadOnlyLocker();
                    emThreadMutex & GetMutex() const;
            private:
                    emThreadMutex & Mutex;
            };

    private:

            enum { MAX_COUNT = 2147483647 };
            emThreadEvent Event;
    };

    inline bool emThreadMutex::Lock(unsigned timeoutMS)
    {
            return Event.Receive(MAX_COUNT,timeoutMS);
    }

    inline bool emThreadMutex::IsLocked() const
    {
            return Event.GetCount()<=0;
    }

    inline bool emThreadMutex::LockReadOnly(unsigned timeoutMS)
    {
            return Event.Receive(1,timeoutMS);
    }

    inline bool emThreadMutex::IsLockedAnyhow() const
    {
            return Event.GetCount()<MAX_COUNT;
    }

    inline emThreadMutex::ReadOnlyLocker::ReadOnlyLocker(emThreadMutex & mutex)
            : Mutex(mutex)
    {
            Mutex.LockReadOnly();
    }

    inline emThreadMutex::ReadOnlyLocker::~ReadOnlyLocker()
    {
            Mutex.UnlockReadOnly();
    }

    inline emThreadMutex & emThreadMutex::ReadOnlyLocker::GetMutex() const
    {
            return Mutex;
    }

    //==============================================================================
    //=========================== emThreadRecursiveMutex ===========================
    //==============================================================================

    class emThreadRecursiveMutex : public emUncopyable {

    public:

            // This is just like emThreadMutex, but it supports recursive locks, and
            // therefore it lacks the readers/writers solution (having the whole
            // luxury would be very costly).

            emThreadRecursiveMutex();
            ~emThreadRecursiveMutex();

            bool Lock(unsigned timeoutMS=UINT_MAX);
            void Unlock();
            bool IsLocked() const;

            typedef emThreadMutexLocker<emThreadRecursiveMutex> Locker;

    private:

            emThreadEvent Event;
            emThreadMiniMutex Mutex;
            emThreadId ThreadId;
            int LockCount;
    };

    inline bool emThreadRecursiveMutex::IsLocked() const
    {
            return Event.GetCount()<=0;
    }

    #endif