rubidium@8934: /* $Id$ */ rubidium@8934: rubidium@8934: /** @file thread_win32.cpp Win32 thread implementation of Threads. */ rubidium@8934: rubidium@8934: #include "stdafx.h" rubidium@8934: #include "thread.h" rubidium@8934: #include "debug.h" rubidium@8934: #include "core/alloc_func.hpp" rubidium@8934: #include rubidium@8934: #include rubidium@8934: #include rubidium@8934: rubidium@8934: /** rubidium@8934: * Win32 thread version for ThreadObject. rubidium@8934: */ rubidium@8934: class ThreadObject_Win32 : public ThreadObject { rubidium@8934: private: rubidium@8934: uint m_id_thr; rubidium@8934: HANDLE m_h_thr; rubidium@8934: OTTDThreadFunc m_proc; rubidium@8934: void *m_param; rubidium@8934: bool m_attached; rubidium@8934: void *ret; rubidium@8934: rubidium@8934: public: rubidium@8934: /** rubidium@8934: * Create a win32 thread and start it, calling proc(param). rubidium@8934: */ rubidium@8934: ThreadObject_Win32(OTTDThreadFunc proc, void *param) : rubidium@8934: m_id_thr(0), rubidium@8934: m_h_thr(NULL), rubidium@8934: m_proc(proc), rubidium@8934: m_param(param), rubidium@8934: m_attached(false) rubidium@8934: { rubidium@8934: m_h_thr = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &m_id_thr); rubidium@8934: if (m_h_thr == NULL) return; rubidium@8934: ResumeThread(m_h_thr); rubidium@8934: } rubidium@8934: rubidium@8934: /** rubidium@8934: * Create a win32 thread and attach current thread to it. rubidium@8934: */ rubidium@8934: ThreadObject_Win32() : rubidium@8934: m_id_thr(0), rubidium@8934: m_h_thr(NULL), rubidium@8934: m_proc(NULL), rubidium@8934: m_param(NULL), rubidium@8934: m_attached(false) rubidium@8934: { rubidium@8934: BOOL ret = DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_h_thr, 0, FALSE, DUPLICATE_SAME_ACCESS); rubidium@8934: if (!ret) return; rubidium@8934: m_id_thr = GetCurrentThreadId(); rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ ~ThreadObject_Win32() rubidium@8934: { rubidium@8934: if (m_h_thr != NULL) { rubidium@8934: CloseHandle(m_h_thr); rubidium@8934: m_h_thr = NULL; rubidium@8934: } rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ bool IsRunning() rubidium@8934: { rubidium@8934: if (m_h_thr == NULL) return false; rubidium@8934: DWORD exit_code = 0; rubidium@8934: if (!GetExitCodeThread(m_h_thr, &exit_code)) return false; rubidium@8934: return (exit_code == STILL_ACTIVE); rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ bool WaitForStop() rubidium@8934: { rubidium@8934: /* You can't wait on yourself */ rubidium@8934: assert(!IsCurrent()); rubidium@8934: /* If the thread is not running, waiting is over */ rubidium@8934: if (!IsRunning()) return true; rubidium@8934: rubidium@8934: DWORD res = WaitForSingleObject(m_h_thr, INFINITE); rubidium@8934: return res == WAIT_OBJECT_0; rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ bool Exit() rubidium@8934: { rubidium@8934: /* You can only exit yourself */ rubidium@8934: assert(IsCurrent()); rubidium@8934: /* If the thread is not running, we are already closed */ rubidium@8934: if (!IsRunning()) return false; rubidium@8934: rubidium@8934: /* For now we terminate by throwing an error, gives much cleaner cleanup */ rubidium@8934: throw 0; rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ void *Join() rubidium@8934: { rubidium@8934: /* You cannot join yourself */ rubidium@8934: assert(!IsCurrent()); rubidium@8934: rubidium@8934: WaitForSingleObject(m_h_thr, INFINITE); rubidium@8934: rubidium@8934: return this->ret; rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ bool IsCurrent() rubidium@8934: { rubidium@8934: DWORD id_cur = GetCurrentThreadId(); rubidium@8934: return id_cur == m_id_thr; rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ uint GetId() rubidium@8934: { rubidium@8934: return m_id_thr; rubidium@8934: } rubidium@8934: rubidium@8934: private: rubidium@8934: /** rubidium@8934: * On thread creation, this function is called, which calls the real startup rubidium@8934: * function. This to get back into the correct instance again. rubidium@8934: */ rubidium@8934: static uint CALLBACK stThreadProc(void *thr) rubidium@8934: { rubidium@8934: return ((ThreadObject_Win32 *)thr)->ThreadProc(); rubidium@8934: } rubidium@8934: rubidium@8934: /** rubidium@8934: * A new thread is created, and this function is called. Call the custom rubidium@8934: * function of the creator of the thread. rubidium@8934: */ rubidium@8934: uint ThreadProc() rubidium@8934: { rubidium@8934: try { rubidium@8934: this->ret = m_proc(m_param); rubidium@8934: } catch (...) { rubidium@8934: } rubidium@8934: rubidium@8934: return 0; rubidium@8934: } rubidium@8934: }; rubidium@8934: rubidium@8934: /* static */ ThreadObject *ThreadObject::New(OTTDThreadFunc proc, void *param) rubidium@8934: { rubidium@8934: return new ThreadObject_Win32(proc, param); rubidium@8934: } rubidium@8934: rubidium@8934: /* static */ ThreadObject* ThreadObject::AttachCurrent() rubidium@8934: { rubidium@8934: return new ThreadObject_Win32(); rubidium@8934: } rubidium@8934: rubidium@8934: /* static */ uint ThreadObject::CurrentId() rubidium@8934: { rubidium@8934: return GetCurrentThreadId(); rubidium@8934: } rubidium@8934: rubidium@8934: rubidium@8934: /** rubidium@8934: * Win32 thread version of ThreadSemaphore. rubidium@8934: */ rubidium@8934: class ThreadSemaphore_Win32 : public ThreadSemaphore { rubidium@8934: private: rubidium@8934: HANDLE m_handle; rubidium@8934: rubidium@8934: public: rubidium@8934: ThreadSemaphore_Win32() rubidium@8934: { rubidium@8934: m_handle = ::CreateEvent(NULL, FALSE, FALSE, NULL); rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ ~ThreadSemaphore_Win32() rubidium@8934: { rubidium@8934: ::CloseHandle(m_handle); rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ void Set() rubidium@8934: { rubidium@8934: ::SetEvent(m_handle); rubidium@8934: } rubidium@8934: rubidium@8934: /* virtual */ void Wait() rubidium@8934: { rubidium@8934: ::WaitForSingleObject(m_handle, INFINITE); rubidium@8934: } rubidium@8934: }; rubidium@8934: rubidium@8934: /* static */ ThreadSemaphore *ThreadSemaphore::New() rubidium@8934: { rubidium@8934: return new ThreadSemaphore_Win32(); rubidium@8934: }