Mercurial > projects > hoofbaby
view deps/Platinum/ThirdParty/Neptune/Source/System/Win32/NptWin32Threads.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line source
/***************************************************************** | | Neptune - Threads :: Win32 Implementation | | (c) 2001-2008 Gilles Boccon-Gibod | Author: Gilles Boccon-Gibod (bok@bok.net) | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #if defined(_XBOX) #include <xtl.h> #else #include <windows.h> #if !defined(_WIN32_WCE) #include <process.h> #endif #endif #include "NptConfig.h" #include "NptTypes.h" #include "NptConstants.h" #include "NptThreads.h" #include "NptDebug.h" #include "NptResults.h" #include "NptWin32Threads.h" #include "NptTime.h" #include "NptSystem.h" #include "NptLogging.h" /*---------------------------------------------------------------------- | logging +---------------------------------------------------------------------*/ NPT_SET_LOCAL_LOGGER("neptune.threads.win32") /*---------------------------------------------------------------------- | configuration macros +---------------------------------------------------------------------*/ #if defined(_WIN32_WCE) || defined(_XBOX) #define NPT_WIN32_USE_CREATE_THREAD #endif #if defined(NPT_WIN32_USE_CREATE_THREAD) #define _beginthreadex(security, stack_size, start_proc, arg, flags, pid) \ CreateThread(security, stack_size, (LPTHREAD_START_ROUTINE) start_proc, \ arg, flags, (LPDWORD)pid) #define _endthreadex ExitThread #endif /*---------------------------------------------------------------------- | NPT_Win32Mutex::NPT_Win32Mutex +---------------------------------------------------------------------*/ NPT_Win32Mutex::NPT_Win32Mutex() { m_Handle = CreateMutex(NULL, FALSE, NULL); } /*---------------------------------------------------------------------- | NPT_Win32Mutex::~NPT_Win32Mutex +---------------------------------------------------------------------*/ NPT_Win32Mutex::~NPT_Win32Mutex() { CloseHandle(m_Handle); } /*---------------------------------------------------------------------- | NPT_Win32Mutex::Lock +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Mutex::Lock() { DWORD result = WaitForSingleObject(m_Handle, INFINITE); if (result == WAIT_OBJECT_0) { return NPT_SUCCESS; } else { return NPT_FAILURE; } } /*---------------------------------------------------------------------- | NPT_Win32Mutex::Unlock +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Mutex::Unlock() { ReleaseMutex(m_Handle); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Mutex::NPT_Mutex +---------------------------------------------------------------------*/ NPT_Mutex::NPT_Mutex() { m_Delegate = new NPT_Win32Mutex(); } /*---------------------------------------------------------------------- | NPT_Win32CriticalSection::NPT_Win32CriticalSection +---------------------------------------------------------------------*/ NPT_Win32CriticalSection::NPT_Win32CriticalSection() { InitializeCriticalSection(&m_CriticalSection); } /*---------------------------------------------------------------------- | NPT_Win32CriticalSection::~NPT_Win32CriticalSection +---------------------------------------------------------------------*/ NPT_Win32CriticalSection::~NPT_Win32CriticalSection() { DeleteCriticalSection(&m_CriticalSection); } /*---------------------------------------------------------------------- | NPT_Win32CriticalSection::Lock +---------------------------------------------------------------------*/ NPT_Result NPT_Win32CriticalSection::Lock() { EnterCriticalSection(&m_CriticalSection); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Win32CriticalSection::Unlock +---------------------------------------------------------------------*/ NPT_Result NPT_Win32CriticalSection::Unlock() { LeaveCriticalSection(&m_CriticalSection); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Win32Event::NPT_Win32Event +---------------------------------------------------------------------*/ NPT_Win32Event::NPT_Win32Event(bool manual /* = false */, bool initial /* = false */) { m_Event = CreateEvent(NULL, (manual==true)?TRUE:FALSE, (initial==true)?TRUE:FALSE, NULL); } /*---------------------------------------------------------------------- | NPT_Win32Event::~NPT_Win32Event +---------------------------------------------------------------------*/ NPT_Win32Event::~NPT_Win32Event() { CloseHandle(m_Event); } /*---------------------------------------------------------------------- | NPT_Win32Event::Wait +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Event::Wait(NPT_Timeout timeout) { if (m_Event) { DWORD result = WaitForSingleObject(m_Event, timeout==NPT_TIMEOUT_INFINITE?INFINITE:timeout); if (result == WAIT_TIMEOUT) { return NPT_ERROR_TIMEOUT; } if (result != WAIT_OBJECT_0 && result != WAIT_ABANDONED) { return NPT_FAILURE; } } return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Win32Event::Signal +---------------------------------------------------------------------*/ void NPT_Win32Event::Signal() { SetEvent(m_Event); } /*---------------------------------------------------------------------- | NPT_Win32Event::Reset +---------------------------------------------------------------------*/ void NPT_Win32Event::Reset() { ResetEvent(m_Event); } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable +---------------------------------------------------------------------*/ class NPT_Win32SharedVariable : public NPT_SharedVariableInterface { public: // methods NPT_Win32SharedVariable(int value); ~NPT_Win32SharedVariable(); void SetValue(int value); int GetValue(); NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); private: // members volatile int m_Value; NPT_Mutex m_Lock; NPT_Win32Event m_Event; }; /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::NPT_Win32SharedVariable +---------------------------------------------------------------------*/ NPT_Win32SharedVariable::NPT_Win32SharedVariable(int value) : m_Value(value) { } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::~NPT_Win32SharedVariable +---------------------------------------------------------------------*/ NPT_Win32SharedVariable::~NPT_Win32SharedVariable() { } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::SetValue +---------------------------------------------------------------------*/ void NPT_Win32SharedVariable::SetValue(int value) { m_Lock.Lock(); if (value != m_Value) { m_Value = value; m_Event.Signal(); } m_Lock.Unlock(); } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::GetValue +---------------------------------------------------------------------*/ int NPT_Win32SharedVariable::GetValue() { // reading an integer should be atomic on all Win32 platforms return m_Value; } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::WaitUntilEquals +---------------------------------------------------------------------*/ NPT_Result NPT_Win32SharedVariable::WaitUntilEquals(int value, NPT_Timeout timeout) { do { m_Lock.Lock(); if (m_Value == value) { break; } m_Lock.Unlock(); { NPT_Result result = m_Event.Wait(timeout); if (NPT_FAILED(result)) return result; } } while (1); m_Lock.Unlock(); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Win32SharedVariable::WaitWhileEquals +---------------------------------------------------------------------*/ NPT_Result NPT_Win32SharedVariable::WaitWhileEquals(int value, NPT_Timeout timeout) { do { m_Lock.Lock(); if (m_Value != value) { break; } m_Lock.Unlock(); { NPT_Result result = m_Event.Wait(timeout); if (NPT_FAILED(result)) return result; } } while (1); m_Lock.Unlock(); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_SharedVariable::NPT_SharedVariable +---------------------------------------------------------------------*/ NPT_SharedVariable::NPT_SharedVariable(int value) { m_Delegate = new NPT_Win32SharedVariable(value); } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable +---------------------------------------------------------------------*/ class NPT_Win32AtomicVariable : public NPT_AtomicVariableInterface { public: // methods NPT_Win32AtomicVariable(int value); ~NPT_Win32AtomicVariable(); int Increment(); int Decrement(); void SetValue(int value); int GetValue(); private: // members volatile LONG m_Value; }; /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::NPT_Win32AtomicVariable +---------------------------------------------------------------------*/ NPT_Win32AtomicVariable::NPT_Win32AtomicVariable(int value) : m_Value(value) { } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::~NPT_Win32AtomicVariable +---------------------------------------------------------------------*/ NPT_Win32AtomicVariable::~NPT_Win32AtomicVariable() { } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::Increment +---------------------------------------------------------------------*/ int NPT_Win32AtomicVariable::Increment() { return InterlockedIncrement(const_cast<LONG*>(&m_Value)); } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::Decrement +---------------------------------------------------------------------*/ int NPT_Win32AtomicVariable::Decrement() { return InterlockedDecrement(const_cast<LONG*>(&m_Value)); } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::SetValue +---------------------------------------------------------------------*/ void NPT_Win32AtomicVariable::SetValue(int value) { m_Value = value; } /*---------------------------------------------------------------------- | NPT_Win32AtomicVariable::GetValue +---------------------------------------------------------------------*/ int NPT_Win32AtomicVariable::GetValue() { return m_Value; } /*---------------------------------------------------------------------- | NPT_AtomicVariable::NPT_AtomicVariable +---------------------------------------------------------------------*/ NPT_AtomicVariable::NPT_AtomicVariable(int value) { m_Delegate = new NPT_Win32AtomicVariable(value); } /*---------------------------------------------------------------------- | NPT_Win32Thread +---------------------------------------------------------------------*/ class NPT_Win32Thread : public NPT_ThreadInterface { public: // methods NPT_Win32Thread(NPT_Thread* delegator, NPT_Runnable& target, bool detached); ~NPT_Win32Thread(); NPT_Result Start(); NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); private: // methods static unsigned int __stdcall EntryPoint(void* argument); // NPT_Runnable methods void Run(); // NPT_Interruptible methods NPT_Result Interrupt() { return NPT_ERROR_NOT_IMPLEMENTED; } // members NPT_Thread* m_Delegator; NPT_Runnable& m_Target; bool m_Detached; HANDLE m_ThreadHandle; DWORD m_ThreadId; }; /*---------------------------------------------------------------------- | NPT_Win32Thread::NPT_Win32Thread +---------------------------------------------------------------------*/ NPT_Win32Thread::NPT_Win32Thread(NPT_Thread* delegator, NPT_Runnable& target, bool detached) : m_Delegator(delegator), m_Target(target), m_Detached(detached), m_ThreadHandle(0), m_ThreadId(0) { } /*---------------------------------------------------------------------- | NPT_Win32Thread::~NPT_Win32Thread +---------------------------------------------------------------------*/ NPT_Win32Thread::~NPT_Win32Thread() { if (!m_Detached) { // we're not detached, and not in the Run() method, so we need to // wait until the thread is done Wait(); } // close the thread handle #if defined(NPT_WIN32_USE_CREATE_THREAD) CloseHandle(m_ThreadHandle); #endif } /*---------------------------------------------------------------------- | NPT_Win32Thread::EntryPoint +---------------------------------------------------------------------*/ unsigned int __stdcall NPT_Win32Thread::EntryPoint(void* argument) { NPT_Win32Thread* thread = reinterpret_cast<NPT_Win32Thread*>(argument); NPT_LOG_FINE("thread in ======================="); // set random seed per thread NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); NPT_System::SetRandomSeed(now.m_NanoSeconds + NPT_Thread::GetCurrentThreadId()); // run the thread thread->Run(); // Logging here will cause a crash on exit because LogManager may already be destroyed //NPT_LOG_FINE("thread out ======================"); // if the thread is detached, delete it if (thread->m_Detached) { delete thread->m_Delegator; } // end the thread _endthreadex(0); // done return 0; } /*---------------------------------------------------------------------- | NPT_Win32Thread::Start +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Thread::Start() { if (m_ThreadHandle > 0) { // failed NPT_LOG_WARNING("thread already started !"); return NPT_ERROR_INVALID_STATE; } NPT_LOG_FINE("creating thread"); // create the native thread #if defined(_WIN32_WCE) DWORD thread_id; #else unsigned int thread_id; #endif // create a stack local detached, as this object // may already be deleted when _beginthreadex returns and // before we get to call detach on the given thread bool detached = m_Detached; m_ThreadHandle = (HANDLE) _beginthreadex(NULL, NPT_CONFIG_THREAD_STACK_SIZE, EntryPoint, reinterpret_cast<void*>(this), 0, &thread_id); if (m_ThreadHandle == 0) { // failed m_ThreadId = 0; return NPT_FAILURE; } if (!detached) { m_ThreadId = (DWORD)thread_id; } return NPT_SUCCESS; } /*---------------------------------------------------------------------- | NPT_Win32Thread::Run +---------------------------------------------------------------------*/ void NPT_Win32Thread::Run() { m_Target.Run(); } /*---------------------------------------------------------------------- | NPT_Win32Thread::Wait +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Thread::Wait(NPT_Timeout timeout /* = NPT_TIMEOUT_INFINITE */) { // check that we're not detached if (m_ThreadHandle == 0 || m_Detached) { return NPT_FAILURE; } // wait for the thread to finish // Logging here will cause a crash on exit because LogManager may already be destroyed //NPT_LOG_FINE_1("joining thread id %d", m_ThreadId); DWORD result = WaitForSingleObject(m_ThreadHandle, timeout==NPT_TIMEOUT_INFINITE?INFINITE:timeout); if (result != WAIT_OBJECT_0) { return NPT_FAILURE; } else { return NPT_SUCCESS; } } /*---------------------------------------------------------------------- | NPT_Thread::GetCurrentThreadId +---------------------------------------------------------------------*/ NPT_Thread::ThreadId NPT_Thread::GetCurrentThreadId() { return ::GetCurrentThreadId(); } /*---------------------------------------------------------------------- | NPT_Thread::NPT_Thread +---------------------------------------------------------------------*/ NPT_Thread::NPT_Thread(bool detached) { m_Delegate = new NPT_Win32Thread(this, *this, detached); } /*---------------------------------------------------------------------- | NPT_Thread::NPT_Thread +---------------------------------------------------------------------*/ NPT_Thread::NPT_Thread(NPT_Runnable& target, bool detached) { m_Delegate = new NPT_Win32Thread(this, target, detached); }