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