// Thread.cpp V0.1pre Provides thread class member functions
// © 2003 Elliot Nierman

#include "thread.h"
Thread::Thread()
{
#ifdef WIN
        T_Var.w_handle = 0;
        T_Var.w_id = 0;
        T_Var.b_susp = true;
        T_Var.b_term = false;
        T_Var.b_created = false;
        T_Var.b_state = CREATED;
#endif

#ifdef POSIX
        T_Var.p_handle = 0;
        T_Var.b_susp = true;
        T_Var.b_term = false;
        T_Var.b_created = false;
        pthread_attr_init(&T_Var.p_attr);
        pthread_mutex_init(&T_Var.p_mux, NULL);
        pthread_cond_init(&T_Var.p_cond, NULL);
#endif
}


// CreateSuspended()
// Description: Creates a thread in a suspended state
bool Thread::CreateSuspended()
{
#ifdef WIN
        T_Var.w_handle = reinterpret_cast<HANDLE>(_beginthreadex( 0, 0,
                                     w_threadfunc, this, CREATE_SUSPENDED, &T_Var.w_id));

#endif

#ifdef POSIX
        pthread_attr_init(&T_Var.p_attr);
        Start_Suspended();
#endif
        return true;
}

// CreateSuspended()
// Description: Creates a thread in a suspended state with an
// associated stack size given by stack_size
bool Thread::CreateSuspended(unsigned long stack_size)
{

#ifdef WIN
        T_Var.w_handle = reinterpret_cast<HANDLE>(_beginthreadex( 0, stack_size,
                                     w_threadfunc, this, CREATE_SUSPENDED, &T_Var.w_id));
#endif

#ifdef POSIX
        pthread_attr_init(&T_Var.p_attr);
        pthread_attr_setstacksize(&T_Var.p_attr, stack_size);
        Start_Suspended();
#endif

        return true;
}

// Create()
// Description: Creates a thread in a running state
bool Thread::Create()
{
#ifdef WIN
        T_Var.b_susp = false;
        T_Var.w_handle = reinterpret_cast<HANDLE>(_beginthreadex( 0, 0,
                                     w_threadfunc, this, 0 , &T_Var.w_id));
#endif

#ifdef POSIX
        pthread_attr_init(&T_Var.p_attr);
        Start();
#endif

return true;
}

// Create(unsigned long stack_size)
// Description: Creates a thread in a running state with a associated
// stack sizeas specified by stack_size
bool Thread::Create(unsigned long stack_size)
{
#ifdef WIN
        T_Var.b_susp = false;
        T_Var.w_handle = reinterpret_cast<HANDLE>(_beginthreadex( 0, stack_size,
                                     w_threadfunc, this, 0 , &T_Var.w_id));

        if (T_Var.w_handle)
            return true;
#endif

#ifdef POSIX
        pthread_attr_init(&T_Var.p_attr);
        pthread_attr_setstacksize(&T_Var.p_attr, stack_size);

        Start();
#endif

        return true;
}

// Execute()
// Description : Called to begin execution of the EntryRoutine()
// of a thread which has been constructed.
bool Thread::Execute()
{
        Resume();
}


// GetID()
// Description: Cross-Platform function which returns the thread ID
// provided by the operating system at thread creation time.
unsigned int Thread::GetID() const
{

#ifdef WIN
        return T_Var.w_id;
#endif


#ifdef POSIX
        while(T_Var.b_created == true && T_Var.p_handle == 0)
            usleep();
        return T_Var.p_handle;
#endif
}


// GetPriority()
// Description: Returns a character pointer corresponding to the
// priority_level of the given thread.
char * Thread::GetPriority()
{

#ifdef POSIX
//This depends on the implemented priority levels
//and must currently be entered by the user
#endif

#ifdef WIN

        switch (T_Var.b_prio)
        {
            case THREAD_PRIORITY_IDLE : return "IDLE";
                                                                    break;
            case THREAD_PRIORITY_LOWEST : return "LOWEST";
                                                                    break;
            case THREAD_PRIORITY_BELOW_NORMAL : return "BELOW_NORMAL";
                                                                    break;
            case THREAD_PRIORITY_NORMAL : return "NORMAL";
                                                                    break;
            case THREAD_PRIORITY_ABOVE_NORMAL : return "ABOVE_NORMAL";
                                                                    break;
            case THREAD_PRIORITY_HIGHEST : return "HIGHEST";
                                                                    break;
            case THREAD_PRIORITY_TIME_CRITICAL : return "TIME_CRITICAL";
                                                                    break;

        }

#endif
        return NULL;
}


// Join()
// Description: Causes the calling thread to be blocked until
// execution of the thread referenced by the call completes.
bool Thread::Join() const
{
#ifdef WIN

        if (WaitForSingleObject(T_Var.w_handle, INFINITE) == WAIT_OBJECT_0)
            return true;
        return false;
#endif

#ifdef POSIX
        pthread_join(GetID(), NULL);
        return true;
#endif
}


// Resume()
// Description: Resumes execution of a thread
// which has been suspended by a call to Suspend()
void Thread::Resume()
{
#ifdef WIN

if (T_Var.b_susp)
{
        T_Var.b_susp = false;
        ResumeThread(T_Var.w_handle);
}

#endif

#ifdef POSIX
        if (!T_Var.b_created)
            Start();
        else
            T_Var.b_susp = false;

        pthread_mutex_lock(&T_Var.p_mux);
        if (T_Var.b_susp == false) pthread_cond_broadcast(&T_Var.p_cond);
            pthread_mutex_unlock(&T_Var.p_mux);
#endif
}

// SafePoint()
// Description: Called by user in the user-overridden function EntryRoutine()
// to indicate a region of code where it is safe to test for and implement
// thread preemption.
void Thread::SafePoint()
{
#ifdef POSIX
        if (T_Var.b_susp)
            Suspend_Thread();
        if (T_Var.b_term)
            pthread_cancel(T_Var.p_handle);
#endif

#ifdef WIN
        if (T_Var.b_susp)
            SuspendThread(T_Var.w_handle);
        if (T_Var.b_term)
            _endthreadex(0);
#endif
}


// SetPriority()
// Description: Sets the priority level of a given thread to the level
// specified with the variable priority level. The enumerated type
// priority_level is defined in thread.h
bool Thread::SetPriority( priority_level priority )
{
#ifdef WIN
        T_Var.b_prio = priority;
        if( SetThreadPriority (T_Var.w_handle, priority) )
            return true;
        else
            return false;
#endif


#ifdef POSIX
// To be posted by 10/29/02
#endif


}

//T_Sleep(unsigned long millisecs)
// Description: Member function adds transparent sleep functionality
// across POSIX/Win32 systems.
void Thread::T_Sleep(unsigned long millisecs)
{
#ifdef WIN
        Sleep(millisecs);
#endif


#ifdef POSIX
usleep(millisecs*1000)
#endif
}

//Terminate()
// Description: Sets a flag to indicate a request for thread termination
// which will be processed on the next call to SafePoint().
void Thread::Terminate()
{
        T_Var.b_term = true;
}


// Suspend()
// Description: Sets a flag to indicate a request for suspension of
// thread execution which is processed on the next call to SafePoint().

void Thread::Suspend()
{
        T_Var.b_susp = true;
}


void Thread::Suspend_Thread()
{

#ifdef POSIX
        pthread_mutex_lock(&T_Var.p_mux);
        while (T_Var.b_susp == true)
                pthread_cond_wait(&T_Var.p_cond, &T_Var.p_mux);
        pthread_mutex_unlock(&T_Var.p_mux);
#endif
}


// w_threadfunc(void *args)
// Description: Private Win32 function which provides the
// object-oriented encapsulation of the thread
#ifdef WIN
unsigned int __stdcall Thread::w_threadfunc(void *args)
{
        Thread *pThread = reinterpret_cast<Thread*>(args);
        if (pThread)
            pThread->ThreadRoutine();
_endthreadex( 0 );
return 0;
}
#endif

// threadfunc(Thread * NewThread)
// Description: Private POSIX Thread threadfunc associated with a
// thread which is created in a running state by Create() on a
// POSIX platform
#ifdef POSIX
void Thread::threadfunc(Thread * NewThread)
{

        NewThread->T_Var.b_susp = false;
        NewThread->ThreadRoutine();
        NewThread->T_Var.b_term = true;

}
#endif

// susp_threadfunc(Thread * NewThread)
// Description: Private POSIX Thread function encapsulating a
// thread which is created in a b_susp state by Construct().
#ifdef POSIX
void Thread::susp_threadfunc(Thread * NewThread)
{
        NewThread->T_Var.b_susp = true;
        NewThread->ThreadRoutine();
        NewThread->T_Var.b_term = true;
}
#endif


// Start()
// Description: Private POSIX function which instantiates a pthread
// in a running state.
#ifdef POSIX
void Thread::Start(void)
{
        T_Var.b_created = true;
        if (pthread_create(&T_Var.p_handle, &T_Var.p_attr, (void *(*)(void*))&threadfunc, this))
            //Thread creation unsucessful
            T_Var.p_handle = 0;
}


#ifdef FIFO
        pthread_attr_setschedpolicy(&T_Var.p_attr, SCHED_FIFO);
#endif

#ifdef RR
         pthread_attr_setschedpolicy(&T_Var.p_attr, SCHED_RR);
#endif

         pthread_attr_setschedparam(&T_Var.p_attr, &T_Var.p_param);
         T_Var.b_created = true;
}
#endif


//Start_Suspended(void)
// Description: Private POSIX member function which instantiates
// a pthread in a suspended state.
#ifdef POSIX
void Thread::Start_Suspended(void)
{

       T_Var.b_created = true;

       if (pthread_create(&T_Var.p_handle, &T_Var.p_attr, (void *(*)(void*))&susp_threadfunc, this))
      {
           T_Var.b_term = true;
           T_Var.p_handle = 0;
       }


#ifdef FIFO
      pthread_attr_setschedpolicy(&p_attr, SCHED_FIFO);
#endif

#ifdef RR
       pthread_attr_setschedpolicy(&p_attr, SCHED_RR);
#endif

       pthread_attr_setschedparam(&T_Var.p_attr, &T_Var.p_param);
       T_Var.b_created = true;

}
#endif