OpenTTD/src/thread_win32.cpp

185 lines
3.6 KiB
C++

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