/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a zlib-style license that can
 *  be found in the License.txt file in the root of the source tree.
 */
 
//---------------------------------------------------------------------------
#include "ZenLib/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#include "ZenLib/Conf_Internal.h"
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#include "ZenLib/Thread.h"
#include <ZenLib/Ztring.h>
#include <ZenLib/CriticalSection.h>
//---------------------------------------------------------------------------
 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ZENLIB_USEWX
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#ifdef ZENLIB_USEWX
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
//---------------------------------------------------------------------------
#include <wx/thread.h>
//---------------------------------------------------------------------------
 
namespace ZenLib
{
 
class ThreadEntry : public wxThread
{
public :
    ThreadEntry(Thread* Th_) : wxThread(wxTHREAD_JOINABLE)
        {Th=Th_;};
    void* Entry() {Th->Entry(); return NULL;}
private :
    Thread* Th;
};
 
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
 
//---------------------------------------------------------------------------
Thread::Thread()
{
    ThreadPointer=(void*)new ThreadEntry(this);
    ((ThreadEntry*)ThreadPointer)->Create();
}
 
//---------------------------------------------------------------------------
Thread::~Thread()
{
    delete (ThreadEntry*)ThreadPointer;
}
 
//***************************************************************************
// Main Entry
//***************************************************************************
 
void Thread::Entry()
{
}
 
//***************************************************************************
// Control
//***************************************************************************
 
void Thread::Run()
{
    ((ThreadEntry*)ThreadPointer)->Resume();
}
 
void Thread::Pause()
{
    ((ThreadEntry*)ThreadPointer)->Pause();
}
 
void Thread::Stop()
{
    ((ThreadEntry*)ThreadPointer)->Delete();
}
 
bool Thread::IsRunning()
{
    return ((ThreadEntry*)ThreadPointer)->IsRunning();
}
 
//***************************************************************************
// Communicating
//***************************************************************************
 
void Thread::Sleep(size_t Millisecond)
{
    ((ThreadEntry*)ThreadPointer)->Sleep((unsigned long)Millisecond);
}
 
void Thread::Yield()
{
    ((ThreadEntry*)ThreadPointer)->Yield();
}
 
} //Namespace
 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// WINDOWS
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#else //ZENLIB_USEWX
#ifdef WINDOWS
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
//---------------------------------------------------------------------------
#undef __TEXT
#include <windows.h>
#undef Yield
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
//Config
 
#ifndef _MT
    #define _MT //Must have this symbol defined to get _beginthread/_endthread declarations
#endif
 
#ifdef __BORLANDC__
    #if !defined(__MT__)
        #define __MT__ //-tWM in the IDE is not always set
    #endif
 
    #if !defined(__MFC_COMPAT__)
        #define __MFC_COMPAT__ // Needed to know about _beginthreadex etc..
    #endif
#endif //__BORLANDC__
 
 
#if  defined(_MSC_VER) || \
    (defined(__GNUG__) && defined(__MSVCRT__)) || \
     defined(__WATCOMC__) || \
     defined(__MWERKS__)
    //(defined(__BORLANDC__) && (__BORLANDC__ >= 0x500))
 
    #ifndef __WXWINCE__
        #define USING_BEGINTHREAD //Using _beginthreadex() instead of CreateThread() if possible (better, because of Win32 API has problems with memory leaks in C library)
    #endif
#endif
 
#ifdef USING_BEGINTHREAD
    #include <process.h>
    typedef unsigned THREAD_RETVAL;     //The return type        of the thread function entry point
    #define THREAD_CALLCONV __stdcall   //The calling convention of the thread function entry point
#else
    // the settings for CreateThread()
    typedef DWORD THREAD_RETVAL;
    #define THREAD_CALLCONV WINAPI
#endif
//---------------------------------------------------------------------------
 
namespace ZenLib
{
 
//---------------------------------------------------------------------------
THREAD_RETVAL THREAD_CALLCONV Thread_Start(void *param)
{
    ((Thread*)param)->Entry();
 
    ((Thread*)param)->Internal_Exit();
 
    return 1;
}
 
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
 
//---------------------------------------------------------------------------
Thread::Thread()
{
    CriticalSectionLocker CSL(C);
    State=State_New;
    ThreadPointer=NULL;
 
}
 
//---------------------------------------------------------------------------
Thread::~Thread()
{
    CriticalSectionLocker CSL(C);
    if (ThreadPointer!=NULL)
        CloseHandle((HANDLE)ThreadPointer); //ThreadPointer=NULL
}
 
//***************************************************************************
// Control
//***************************************************************************
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::Run()
{
    CriticalSectionLocker CSL(C);
 
    //Coherency
    if (State!=State_New || ThreadPointer!=NULL)
    {
        return Incoherent;
    }
 
    //Creating
    #ifdef USING_BEGINTHREAD
        #ifdef __WATCOMC__
            const unsigned stksize=10240; //Watcom is reported to not like 0 stack size (which means "use default")
        #else
            const unsigned stksize=0; //Default
        #endif //__WATCOMC__
 
        ThreadPointer=(void*)_beginthreadex (NULL, stksize, Thread_Start, this, CREATE_SUSPENDED, NULL);
    #else
        ThreadPointer=(void*)CreateThread   (NULL,       0, Thread_Start, this, CREATE_SUSPENDED, NULL);
    #endif //USING_BEGINTHREAD
    if (ThreadPointer==NULL)
    {
        return Resource;
    }
 
    //Running
    ResumeThread((HANDLE)ThreadPointer);
 
    //Configuring
    State=State_Running;
 
    return Ok;
}
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::RunAgain()
{
    //Coherency
    {
        CriticalSectionLocker CSL(C);
 
        //Coherency
        if (State != State_New
            && State != State_Terminated)
        {
            return Incoherent;
        }
 
        //Configuring
        if (State == State_Terminated)
            State = State_New;
    }
    return Run();
}
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::Pause()
{
    CriticalSectionLocker CSL(C);
 
    //Pausing
    SuspendThread((HANDLE)ThreadPointer);
 
    //Configuring
    State=State_Paused;
 
    return Ok;
}
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::RequestTerminate()
{
    CriticalSectionLocker CSL(C);
 
    //Coherency
    if (State!=State_Running)
    {
        return IsNotRunning;
    }
 
    //Configuring
    State=State_Terminating;
 
    return Ok;
}
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::ForceTerminate()
{
    #ifdef WINDOWS_UWP
        return Incoherent;
    #else
        CriticalSectionLocker CSL(C);
 
        //Terminating (not clean)
        TerminateThread((HANDLE)ThreadPointer, 1);
        ThreadPointer=NULL;
 
        //Configuring
        State=State_Terminated;
 
        return Ok;
    #endif
}
 
//***************************************************************************
// Status
//***************************************************************************
 
bool Thread::IsRunning()
{
    return State==State_Running;
}
 
//---------------------------------------------------------------------------
bool Thread::IsTerminating()
{
    return State==State_Terminating;
}
 
//---------------------------------------------------------------------------
bool Thread::IsExited()
{
    return State==State_Terminated;
}
 
//***************************************************************************
// Main Entry
//***************************************************************************
 
void Thread::Entry()
{
}
 
//***************************************************************************
// Communicating
//***************************************************************************
 
//---------------------------------------------------------------------------
void Thread::Sleep(size_t Millisecond)
{
    ::Sleep((DWORD)Millisecond);
}
 
//---------------------------------------------------------------------------
void Thread::Yield()
{
    ::Sleep(0);
}
 
//***************************************************************************
// Internal
//***************************************************************************
 
//---------------------------------------------------------------------------
Thread::returnvalue Thread::Internal_Exit()
{
    CriticalSectionLocker CSL(C);
 
    //Coherency
    if (State!=State_Running
     && State!=State_Terminating)
    {
        return IsNotRunning;
    }
 
    //Closing old handle
    CloseHandle((HANDLE)ThreadPointer); ThreadPointer=NULL;
 
    //Configuring
    State=State_Terminated;
 
    return Ok;
}
 
} //Namespace
 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// UNIX
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#else //WINDOWS
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
//---------------------------------------------------------------------------
//Source: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#include <pthread.h>
#include <unistd.h>
#ifdef _POSIX_PRIORITY_SCHEDULING
    #include <sched.h>
#endif //_POSIX_PRIORITY_SCHEDULING
//---------------------------------------------------------------------------
 
namespace ZenLib
{
 
//---------------------------------------------------------------------------
void *Thread_Start(void *param)
{
    ((Thread*)param)->Entry();
    ((Thread*)param)->Internal_Exit();
 
    return NULL;
}
 
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
 
//---------------------------------------------------------------------------
Thread::Thread()
{
    CriticalSectionLocker CSL(C);
 
    State=State_New;
    ThreadPointer=NULL;
 
}
 
//---------------------------------------------------------------------------
Thread::~Thread()
{
}
 
//***************************************************************************
// Main Entry
//***************************************************************************
 
void Thread::Entry()
{
}
 
//***************************************************************************
// Control
//***************************************************************************
 
Thread::returnvalue Thread::Run()
{
    CriticalSectionLocker CSL(C);
 
    //Coherency
    if (State!=State_New || ThreadPointer!=NULL)
    {
        return Incoherent;
    }
 
    //Creating
    pthread_attr_t Attr;
    pthread_attr_init(&Attr);
    pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
 
    //Running
    pthread_create((pthread_t*)&ThreadPointer, &Attr, Thread_Start, (void*)this);
 
    //Configuring
    State=State_Running;
 
    return Ok;
}
 
Thread::returnvalue Thread::RunAgain()
{
    {
        //Coherency
        CriticalSectionLocker CSL(C);
 
        //Coherency
        if (State!=State_New
        && State!=State_Terminated)
        {
            return Incoherent;
        }
 
        //Configuring
        if (State==State_Terminated)
            State=State_New;
    }
 
    return Run();
}
 
Thread::returnvalue Thread::Pause()
{
    //pthread_cond_wait
    return Ok;
}
 
Thread::returnvalue Thread::RequestTerminate()
{
    CriticalSectionLocker CSL(C);
 
    if (State!=State_Running)
    {
        return IsNotRunning;
    }
 
    State=State_Terminating;
 
    return Ok;
}
 
Thread::returnvalue Thread::ForceTerminate()
{
    //Terminating (not clean)
    #if !defined(__ANDROID_API__)
    pthread_cancel((pthread_t)ThreadPointer);
    #endif
 
    //Configuring
    State=State_Terminated;
 
    return Ok;
}
 
//***************************************************************************
// Status
//***************************************************************************
 
//---------------------------------------------------------------------------
bool Thread::IsRunning()
{
    return State==State_Running;
}
 
//---------------------------------------------------------------------------
bool Thread::IsTerminating()
{
    return State==State_Terminating;
}
 
//---------------------------------------------------------------------------
bool Thread::IsExited()
{
    return State==State_Terminated;
}
 
//***************************************************************************
// Communicating
//***************************************************************************
 
void Thread::Sleep(size_t Millisecond)
{
    usleep(Millisecond*1000);
}
 
void Thread::Yield()
{
    #ifdef _POSIX_PRIORITY_SCHEDULING
        sched_yield();
    #endif //_POSIX_PRIORITY_SCHEDULING
}
 
//***************************************************************************
// Internal
//***************************************************************************
 
Thread::returnvalue Thread::Internal_Exit()
{
    CriticalSectionLocker CSL(C);
 
    //Coherency
    if (State!=State_Running
     && State!=State_Terminating)
    {
        return IsNotRunning;
    }
 
    //Closing old handle
    ThreadPointer=NULL;
 
    //Configuring
    State=State_Terminated;
 
    return Ok;
}
 
} //Namespace
 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#endif //WINDOWS
#endif //ZENLIB_USEWX
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

V720 It is advised to utilize the 'SuspendThread' function only when developing a debugger (see documentation for details).