summaryrefslogtreecommitdiffstats
path: root/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp')
-rw-r--r--lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp704
1 files changed, 704 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp b/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp
new file mode 100644
index 0000000..3ab979a
--- /dev/null
+++ b/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Threads.cpp
@@ -0,0 +1,704 @@
+/*****************************************************************
+|
+| 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(bool recursive)
+{
+ NPT_COMPILER_UNUSED(recursive); // always recursive on Win32
+ 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);
+ NPT_Result WaitWhileOrUntilEquals(int value, NPT_Timeout timeout, bool until);
+
+ private:
+ // members
+ volatile int m_Value;
+ volatile unsigned int m_Waiters;
+ NPT_Mutex m_Lock;
+ NPT_Win32Event m_Event;
+};
+
+/*----------------------------------------------------------------------
+| NPT_Win32SharedVariable::NPT_Win32SharedVariable
++---------------------------------------------------------------------*/
+NPT_Win32SharedVariable::NPT_Win32SharedVariable(int value) :
+ m_Value(value),
+ m_Waiters(0),
+ m_Event(true)
+{
+}
+
+/*----------------------------------------------------------------------
+| 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;
+ if (m_Waiters) 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::WaitWhileOrUntilEquals
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32SharedVariable::WaitWhileOrUntilEquals(int value, NPT_Timeout timeout, bool until)
+{
+ do {
+ m_Lock.Lock();
+ if (until) {
+ if (m_Value == value) break;
+ } else {
+ if (m_Value != value) break;
+ }
+ ++m_Waiters;
+ m_Lock.Unlock();
+
+ NPT_Result result = m_Event.Wait(timeout);
+ bool last_waiter = true;
+ m_Lock.Lock();
+ if (--m_Waiters == 0) {
+ m_Event.Reset();
+ } else {
+ last_waiter = false;
+ }
+ m_Lock.Unlock();
+
+ if (NPT_FAILED(result)) return result;
+
+ // FIXME: this is suboptimal, but we need it to ensure we don't busy-loop
+ if (!last_waiter) {
+ Sleep(10);
+ }
+ } while (true);
+
+ m_Lock.Unlock();
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32SharedVariable::WaitUntilEquals
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32SharedVariable::WaitUntilEquals(int value, NPT_Timeout timeout)
+{
+ return WaitWhileOrUntilEquals(value, timeout, true);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32SharedVariable::WaitWhileEquals
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32SharedVariable::WaitWhileEquals(int value, NPT_Timeout timeout)
+{
+ return WaitWhileOrUntilEquals(value, timeout, false);
+}
+
+/*----------------------------------------------------------------------
+| 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:
+ // class methods
+ static NPT_Result SetThreadPriority(HANDLE thread, int priority);
+ static NPT_Result GetThreadPriority(HANDLE thread, int& priority);
+
+ // 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);
+ NPT_Result GetPriority(int& priority);
+ NPT_Result SetPriority(int priority);
+ NPT_Result CancelBlockerSocket();
+
+ 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(nullptr),
+ 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 (m_ThreadHandle) {
+ CloseHandle(m_ThreadHandle);
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::SetThreadPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::SetThreadPriority(HANDLE thread, int priority)
+{
+ int win32_priority;
+ if (priority < NPT_THREAD_PRIORITY_LOWEST) {
+ win32_priority = THREAD_PRIORITY_IDLE;
+ } else if (priority < NPT_THREAD_PRIORITY_BELOW_NORMAL) {
+ win32_priority = THREAD_PRIORITY_LOWEST;
+ } else if (priority < NPT_THREAD_PRIORITY_NORMAL) {
+ win32_priority = THREAD_PRIORITY_BELOW_NORMAL;
+ } else if (priority < NPT_THREAD_PRIORITY_ABOVE_NORMAL) {
+ win32_priority = THREAD_PRIORITY_NORMAL;
+ } else if (priority < NPT_THREAD_PRIORITY_HIGHEST) {
+ win32_priority = THREAD_PRIORITY_ABOVE_NORMAL;
+ } else if (priority < NPT_THREAD_PRIORITY_TIME_CRITICAL) {
+ win32_priority = THREAD_PRIORITY_HIGHEST;
+ } else {
+ win32_priority = THREAD_PRIORITY_TIME_CRITICAL;
+ }
+ BOOL result = ::SetThreadPriority(thread, win32_priority);
+ if (!result) {
+ NPT_LOG_WARNING_1("SetThreadPriority failed (%x)", GetLastError());
+ return NPT_FAILURE;
+ }
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::GetThreadPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::GetThreadPriority(HANDLE thread, int& priority)
+{
+ int win32_priority = ::GetThreadPriority(thread);
+ if (win32_priority == THREAD_PRIORITY_ERROR_RETURN) {
+ NPT_LOG_WARNING_1("GetThreadPriority failed (%x)", GetLastError());
+ return NPT_FAILURE;
+ }
+
+ priority = win32_priority;
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::EntryPoint
++---------------------------------------------------------------------*/
+unsigned int __stdcall
+NPT_Win32Thread::EntryPoint(void* argument)
+{
+ NPT_Win32Thread* thread = reinterpret_cast<NPT_Win32Thread*>(argument);
+
+ NPT_LOG_FINER("thread in =======================");
+
+ // set random seed per thread
+ NPT_TimeStamp now;
+ NPT_System::GetCurrentTimeStamp(now);
+ NPT_System::SetRandomSeed((NPT_UInt32)(now.ToNanos()) + ::GetCurrentThreadId());
+
+ // set a default name
+ #pragma pack(push,8)
+ struct THREADNAME_INFO
+ {
+ DWORD dwType; // must be 0x1000
+ LPCSTR szName; // pointer to name (in same addr space)
+ DWORD dwThreadID; // thread ID (-1 caller thread)
+ DWORD dwFlags; // reserved for future use, most be zero
+ } info;
+ #pragma pack(pop)
+ info.dwType = 0x1000;
+ info.szName = "Neptune Thread";
+ info.dwThreadID = GetCurrentThreadId();
+ info.dwFlags = 0;
+ __try
+ {
+ RaiseException(0x406d1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+
+ thread->m_ThreadId = (DWORD)::GetCurrentThreadId();
+
+ // run the thread
+ thread->Run();
+
+ // if the thread is detached, delete it
+ if (thread->m_Detached) {
+ delete thread->m_Delegator;
+ }
+
+ // done
+ return 0;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::Start
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::Start()
+{
+ if (m_ThreadHandle != nullptr) {
+ // failed
+ NPT_LOG_WARNING("thread already started !");
+ return NPT_ERROR_INVALID_STATE;
+ }
+
+ NPT_LOG_FINER("creating thread");
+
+ // create the native thread
+#if defined(_WIN32_WCE)
+ DWORD thread_id;
+#else
+ unsigned int thread_id;
+#endif
+ // create a stack local variable '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;
+
+ HANDLE thread_handle = (HANDLE)
+ _beginthreadex(NULL,
+ NPT_CONFIG_THREAD_STACK_SIZE,
+ EntryPoint,
+ reinterpret_cast<void*>(this),
+ 0,
+ &thread_id);
+ if (thread_handle == 0) {
+ // failed
+ return NPT_FAILURE;
+ }
+
+ if (detached) {
+ CloseHandle(thread_handle);
+ } else {
+ m_ThreadHandle = thread_handle;
+ }
+
+ m_ThreadId = (DWORD)thread_id;
+
+ return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::Run
++---------------------------------------------------------------------*/
+void
+NPT_Win32Thread::Run()
+{
+ m_Target.Run();
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::SetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::SetPriority(int priority)
+{
+ if (m_ThreadHandle == 0) return NPT_ERROR_INVALID_STATE;
+ return NPT_Win32Thread::SetThreadPriority(m_ThreadHandle, priority);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::GetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::GetPriority(int& priority)
+{
+ if (m_ThreadHandle == 0) return NPT_ERROR_INVALID_STATE;
+ return NPT_Win32Thread::GetThreadPriority(m_ThreadHandle, priority);
+}
+
+/*----------------------------------------------------------------------
+| 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
+ DWORD result = WaitForSingleObject(m_ThreadHandle,
+ timeout==NPT_TIMEOUT_INFINITE?INFINITE:timeout);
+ if (result != WAIT_OBJECT_0) {
+ return NPT_FAILURE;
+ } else {
+ return NPT_SUCCESS;
+ }
+}
+
+/*----------------------------------------------------------------------
+| NPT_Win32Thread::CancelBlockerSocket
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Win32Thread::CancelBlockerSocket()
+{
+ return NPT_Socket::CancelBlockerSocket((NPT_Thread::ThreadId)m_ThreadId);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Thread::GetCurrentThreadId
++---------------------------------------------------------------------*/
+NPT_Thread::ThreadId
+NPT_Thread::GetCurrentThreadId()
+{
+ return ::GetCurrentThreadId();
+}
+
+/*----------------------------------------------------------------------
+| NPT_Thread::SetCurrentThreadPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Thread::SetCurrentThreadPriority(int priority)
+{
+ return NPT_Win32Thread::SetThreadPriority(::GetCurrentThread(), priority);
+}
+
+/*----------------------------------------------------------------------
+| 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);
+}