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