truebrain@9859: /* $Id$ */ truebrain@9859: truebrain@9859: /** @file fiber_win32.cpp Win32 implementation of Fiber. */ truebrain@9859: truebrain@9859: #include "stdafx.h" truebrain@9859: #include "fiber.hpp" truebrain@9859: #include truebrain@9859: #include truebrain@9859: #include truebrain@9859: truebrain@9859: class Fiber_Win32 : public Fiber { truebrain@9859: private: truebrain@9859: LPVOID m_fiber; truebrain@9859: FiberFunc m_proc; truebrain@9859: void *m_param; truebrain@9859: bool m_attached; truebrain@9859: truebrain@9859: static Fiber_Win32 *s_main; truebrain@9859: truebrain@9859: public: truebrain@9859: /** truebrain@9859: * Create a win32 fiber and start it, calling proc(param). truebrain@9859: */ truebrain@9859: Fiber_Win32(FiberFunc proc, void *param) : truebrain@9859: m_fiber(NULL), truebrain@9859: m_proc(proc), truebrain@9859: m_param(param), truebrain@9859: m_attached(false) truebrain@9859: { truebrain@9859: CreateFiber(); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Create a win32 fiber and attach current thread to it. truebrain@9859: */ truebrain@9859: Fiber_Win32(void *param) : truebrain@9859: m_fiber(NULL), truebrain@9859: m_proc(NULL), truebrain@9859: m_param(param), truebrain@9859: m_attached(true) truebrain@9859: { truebrain@9859: ConvertThreadToFiber(); truebrain@9859: if (s_main == NULL) s_main = this; truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ ~Fiber_Win32() truebrain@9859: { truebrain@9859: if (this->m_fiber != NULL) { truebrain@9859: if (this->m_attached) { truebrain@9859: this->ConvertFiberToThread(); truebrain@9859: } else { truebrain@9859: this->DeleteFiber(); truebrain@9859: } truebrain@9859: } truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void SwitchToFiber() truebrain@9859: { truebrain@9859: typedef VOID (WINAPI *FnSwitchToFiber)(LPVOID fiber); truebrain@9859: truebrain@9859: static FnSwitchToFiber fnSwitchToFiber = (FnSwitchToFiber)stGetProcAddr("SwitchToFiber"); truebrain@9859: assert(fnSwitchToFiber != NULL); truebrain@9859: truebrain@9859: fnSwitchToFiber(this->m_fiber); truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void Exit() truebrain@9859: { truebrain@9859: /* Simply switch back to the main fiber, we kill the fiber sooner or later */ truebrain@9859: s_main->SwitchToFiber(); truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ bool IsRunning() truebrain@9859: { truebrain@9859: return this->m_fiber != NULL; truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void *GetFiberData() truebrain@9859: { truebrain@9859: return this->m_param; truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Win95 doesn't have Fiber support. So check if we have Fiber support, truebrain@9859: * and else fall back on Fiber_Thread. truebrain@9859: */ truebrain@9859: static bool IsSupported() truebrain@9859: { truebrain@9859: static bool first_run = true; truebrain@9859: static bool is_supported = false; truebrain@9859: truebrain@9859: if (first_run) { truebrain@9859: first_run = false; truebrain@9859: static const char *names[] = { truebrain@9859: "ConvertThreadToFiber", truebrain@9859: "CreateFiber", truebrain@9859: "DeleteFiber", truebrain@9859: "ConvertFiberToThread", truebrain@9859: "SwitchToFiber"}; truebrain@9859: for (size_t i = 0; i < lengthof(names); i++) { truebrain@9859: if (stGetProcAddr(names[i]) == NULL) return false; truebrain@9859: } truebrain@9859: is_supported = true; truebrain@9859: } truebrain@9859: return is_supported; truebrain@9859: } truebrain@9859: truebrain@9859: private: truebrain@9859: /** truebrain@9859: * Get a function from kernel32.dll. truebrain@9859: * @param name Function to get. truebrain@9859: * @return Proc to the function, or NULL when not found. truebrain@9859: */ truebrain@9859: static FARPROC stGetProcAddr(const char *name) truebrain@9859: { truebrain@9859: static HMODULE hKernel = LoadLibraryA("kernel32.dll"); truebrain@9859: return GetProcAddress(hKernel, name); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * First function which is called within the fiber. truebrain@9859: */ truebrain@9859: static VOID CALLBACK stFiberProc(LPVOID fiber) truebrain@9859: { truebrain@9859: Fiber_Win32 *cur = (Fiber_Win32 *)fiber; truebrain@9859: cur->m_proc(cur->m_param); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Delete a fiber. truebrain@9859: */ truebrain@9859: void DeleteFiber() truebrain@9859: { truebrain@9859: typedef VOID (WINAPI *FnDeleteFiber)(LPVOID lpFiber); truebrain@9859: truebrain@9859: static FnDeleteFiber fnDeleteFiber = (FnDeleteFiber)stGetProcAddr("DeleteFiber"); truebrain@9859: assert(fnDeleteFiber != NULL); truebrain@9859: truebrain@9859: fnDeleteFiber(this->m_fiber); truebrain@9859: this->m_fiber = NULL; truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Convert a current thread to a fiber. truebrain@9859: */ truebrain@9859: void ConvertThreadToFiber() truebrain@9859: { truebrain@9859: typedef LPVOID (WINAPI *FnConvertThreadToFiber)(LPVOID lpParameter); truebrain@9859: truebrain@9859: static FnConvertThreadToFiber fnConvertThreadToFiber = (FnConvertThreadToFiber)stGetProcAddr("ConvertThreadToFiber"); truebrain@9859: assert(fnConvertThreadToFiber != NULL); truebrain@9859: truebrain@9859: this->m_fiber = fnConvertThreadToFiber(this); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Create a new fiber. truebrain@9859: */ truebrain@9859: void CreateFiber() truebrain@9859: { truebrain@9859: typedef LPVOID (WINAPI *FnCreateFiber)(SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter); truebrain@9859: truebrain@9859: static FnCreateFiber fnCreateFiber = (FnCreateFiber)stGetProcAddr("CreateFiber"); truebrain@9859: assert(fnCreateFiber != NULL); truebrain@9859: truebrain@9859: this->m_fiber = fnCreateFiber(0, &stFiberProc, this); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Convert a fiber back to a thread. truebrain@9859: */ truebrain@9859: void ConvertFiberToThread() truebrain@9859: { truebrain@9859: typedef BOOL (WINAPI *FnConvertFiberToThread)(); truebrain@9859: truebrain@9859: static FnConvertFiberToThread fnConvertFiberToThread = (FnConvertFiberToThread)stGetProcAddr("ConvertFiberToThread"); truebrain@9859: assert(fnConvertFiberToThread != NULL); truebrain@9859: truebrain@9859: fnConvertFiberToThread(); truebrain@9859: this->m_fiber = NULL; truebrain@9859: } truebrain@9859: }; truebrain@9859: truebrain@9859: /* Initialize the static member of Fiber_Win32 */ truebrain@9859: /* static */ Fiber_Win32 *Fiber_Win32::s_main = NULL; truebrain@9859: truebrain@9859: /* Include Fiber_Thread, as Win95 needs it */ truebrain@9859: #include "fiber_thread.cpp" truebrain@9859: truebrain@9859: /* static */ Fiber *Fiber::New(FiberFunc proc, void *param) truebrain@9859: { truebrain@9859: if (Fiber_Win32::IsSupported()) return new Fiber_Win32(proc, param); truebrain@9859: return new Fiber_Thread(proc, param); truebrain@9859: } truebrain@9859: truebrain@9859: /* static */ Fiber *Fiber::AttachCurrent(void *param) truebrain@9859: { truebrain@9859: if (Fiber_Win32::IsSupported()) return new Fiber_Win32(param); truebrain@9859: return new Fiber_Thread(param); truebrain@9859: } truebrain@9859: truebrain@9859: /* static */ void *Fiber::GetCurrentFiberData() truebrain@9859: { truebrain@9859: if (Fiber_Win32::IsSupported()) return ((Fiber *)::GetFiberData())->GetFiberData(); truebrain@9859: return Fiber_Thread::GetCurrentFiber()->GetFiberData(); truebrain@9859: }