truebrain@9859: /* $Id$ */ truebrain@9859: truebrain@9859: /** @file fiber_thread.cpp ThreadObject implementation of Fiber. */ truebrain@9859: truebrain@9859: #include "stdafx.h" truebrain@9859: #include "fiber.hpp" truebrain@9859: #include "thread.h" truebrain@9859: #include truebrain@9859: truebrain@9859: class Fiber_Thread : public Fiber { truebrain@9859: private: truebrain@9859: ThreadObject *m_thread; truebrain@9859: FiberFunc m_proc; truebrain@9859: void *m_param; truebrain@9859: bool m_attached; truebrain@9859: ThreadSemaphore *m_sem; truebrain@9859: bool m_kill; truebrain@9859: truebrain@9859: static Fiber_Thread *s_current; truebrain@9859: static Fiber_Thread *s_main; truebrain@9859: truebrain@9859: public: truebrain@9859: /** truebrain@9859: * Create a ThreadObject fiber and start it, calling proc(param). truebrain@9859: */ truebrain@9859: Fiber_Thread(FiberFunc proc, void *param) : truebrain@9859: m_thread(NULL), truebrain@9859: m_proc(proc), truebrain@9859: m_param(param), truebrain@9859: m_attached(false), truebrain@9859: m_kill(false) truebrain@9859: { truebrain@9859: this->m_sem = ThreadSemaphore::New(); truebrain@9859: /* Create a thread and start stFiberProc */ truebrain@9859: this->m_thread = ThreadObject::New(&stFiberProc, this); truebrain@9859: } truebrain@9859: truebrain@9859: /** truebrain@9859: * Create a ThreadObject fiber and attach current thread to it. truebrain@9859: */ truebrain@9859: Fiber_Thread(void *param) : truebrain@9859: m_thread(NULL), truebrain@9859: m_proc(NULL), truebrain@9859: m_param(param), truebrain@9859: m_attached(true), truebrain@9859: m_kill(false) truebrain@9859: { truebrain@9859: this->m_sem = ThreadSemaphore::New(); truebrain@9859: /* Attach the current thread to this Fiber */ truebrain@9859: this->m_thread = ThreadObject::AttachCurrent(); truebrain@9859: /* We are the current thread */ truebrain@9859: if (s_current == NULL) s_current = this; truebrain@9859: if (s_main == NULL) s_main = this; truebrain@9859: } truebrain@9859: truebrain@9859: ~Fiber_Thread() truebrain@9859: { truebrain@9859: /* Remove the thread if needed */ truebrain@9859: if (this->m_thread != NULL) { truebrain@9859: assert(this->m_attached || !this->m_thread->IsRunning()); truebrain@9859: delete this->m_thread; truebrain@9859: } truebrain@9859: /* Remove the semaphore */ truebrain@9859: delete this->m_sem; truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void SwitchToFiber() truebrain@9859: { truebrain@9859: /* You can't switch to yourself */ truebrain@9859: assert(s_current != this); truebrain@9859: Fiber_Thread *cur = s_current; truebrain@9859: truebrain@9859: /* Continue the execution of 'this' Fiber */ truebrain@9859: this->m_sem->Set(); truebrain@9859: /* Hold the execution of the current Fiber */ truebrain@9859: cur->m_sem->Wait(); truebrain@9859: if (this->m_kill) { truebrain@9859: /* If the thread we switched too was killed, join it so it can finish quiting */ truebrain@9859: this->m_thread->Join(); truebrain@9859: } truebrain@9859: /* If we continue, we are the current thread */ truebrain@9859: s_current = cur; truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void Exit() truebrain@9859: { truebrain@9859: /* Kill off our thread */ truebrain@9859: this->m_kill = true; truebrain@9859: this->m_thread->Exit(); truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ bool IsRunning() truebrain@9859: { truebrain@9859: if (this->m_thread == NULL) return false; truebrain@9859: return this->m_thread->IsRunning(); truebrain@9859: } truebrain@9859: truebrain@9859: /* virtual */ void *GetFiberData() truebrain@9859: { truebrain@9859: return this->m_param; truebrain@9859: } truebrain@9859: truebrain@9859: static Fiber_Thread *GetCurrentFiber() truebrain@9859: { truebrain@9859: return s_current; truebrain@9859: } truebrain@9859: truebrain@9859: private: truebrain@9859: /** truebrain@9859: * First function which is called within the fiber. truebrain@9859: */ truebrain@9859: static void * CDECL stFiberProc(void *fiber) truebrain@9859: { truebrain@9859: Fiber_Thread *cur = (Fiber_Thread *)fiber; truebrain@9859: /* Now suspend the thread until we get SwitchToFiber() for the first time */ truebrain@9859: cur->m_sem->Wait(); truebrain@9859: /* If we continue, we are the current thread */ truebrain@9859: s_current = cur; truebrain@9859: truebrain@9859: try { truebrain@9859: cur->m_proc(cur->m_param); truebrain@9859: } catch (...) { truebrain@9859: /* Unlock the main thread */ truebrain@9859: s_main->m_sem->Set(); truebrain@9859: throw; truebrain@9859: } truebrain@9859: truebrain@9859: return NULL; truebrain@9859: } truebrain@9859: }; truebrain@9859: truebrain@9859: /* Initialize the static member of Fiber_Thread */ truebrain@9859: /* static */ Fiber_Thread *Fiber_Thread::s_current = NULL; truebrain@9859: /* static */ Fiber_Thread *Fiber_Thread::s_main = NULL; truebrain@9859: truebrain@9859: #ifndef WIN32 truebrain@9859: truebrain@9859: /* static */ Fiber *Fiber::New(FiberFunc proc, void *param) truebrain@9859: { truebrain@9859: return new Fiber_Thread(proc, param); truebrain@9859: } truebrain@9859: truebrain@9859: /* static */ Fiber *Fiber::AttachCurrent(void *param) truebrain@9859: { truebrain@9859: return new Fiber_Thread(param); truebrain@9859: } truebrain@9859: truebrain@9859: /* static */ void *Fiber::GetCurrentFiberData() truebrain@9859: { truebrain@9859: return Fiber_Thread::GetCurrentFiber()->GetFiberData(); truebrain@9859: } truebrain@9859: truebrain@9859: #endif /* WIN32 */