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