src/fiber_thread.cpp
branchnoai
changeset 9859 81621c6ba0e9
child 10860 ae89867701fe
equal deleted inserted replaced
9858:b385c3ee0926 9859:81621c6ba0e9
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file fiber_thread.cpp ThreadObject implementation of Fiber. */
       
     4 
       
     5 #include "stdafx.h"
       
     6 #include "fiber.hpp"
       
     7 #include "thread.h"
       
     8 #include <stdlib.h>
       
     9 
       
    10 class Fiber_Thread : public Fiber {
       
    11 private:
       
    12 	ThreadObject *m_thread;
       
    13 	FiberFunc m_proc;
       
    14 	void *m_param;
       
    15 	bool m_attached;
       
    16 	ThreadSemaphore *m_sem;
       
    17 	bool m_kill;
       
    18 
       
    19 	static Fiber_Thread *s_current;
       
    20 	static Fiber_Thread *s_main;
       
    21 
       
    22 public:
       
    23 	/**
       
    24 	 * Create a ThreadObject fiber and start it, calling proc(param).
       
    25 	 */
       
    26 	Fiber_Thread(FiberFunc proc, void *param) :
       
    27 		m_thread(NULL),
       
    28 		m_proc(proc),
       
    29 		m_param(param),
       
    30 		m_attached(false),
       
    31 		m_kill(false)
       
    32 	{
       
    33 		this->m_sem = ThreadSemaphore::New();
       
    34 		/* Create a thread and start stFiberProc */
       
    35 		this->m_thread = ThreadObject::New(&stFiberProc, this);
       
    36 	}
       
    37 
       
    38 	/**
       
    39 	 * Create a ThreadObject fiber and attach current thread to it.
       
    40 	 */
       
    41 	Fiber_Thread(void *param) :
       
    42 		m_thread(NULL),
       
    43 		m_proc(NULL),
       
    44 		m_param(param),
       
    45 		m_attached(true),
       
    46 		m_kill(false)
       
    47 	{
       
    48 		this->m_sem = ThreadSemaphore::New();
       
    49 		/* Attach the current thread to this Fiber */
       
    50 		this->m_thread = ThreadObject::AttachCurrent();
       
    51 		/* We are the current thread */
       
    52 		if (s_current == NULL) s_current = this;
       
    53 		if (s_main == NULL) s_main = this;
       
    54 	}
       
    55 
       
    56 	~Fiber_Thread()
       
    57 	{
       
    58 		/* Remove the thread if needed */
       
    59 		if (this->m_thread != NULL) {
       
    60 			assert(this->m_attached || !this->m_thread->IsRunning());
       
    61 			delete this->m_thread;
       
    62 		}
       
    63 		/* Remove the semaphore */
       
    64 		delete this->m_sem;
       
    65 	}
       
    66 
       
    67 	/* virtual */ void SwitchToFiber()
       
    68 	{
       
    69 		/* You can't switch to yourself */
       
    70 		assert(s_current != this);
       
    71 		Fiber_Thread *cur = s_current;
       
    72 
       
    73 		/* Continue the execution of 'this' Fiber */
       
    74 		this->m_sem->Set();
       
    75 		/* Hold the execution of the current Fiber */
       
    76 		cur->m_sem->Wait();
       
    77 		if (this->m_kill) {
       
    78 			/* If the thread we switched too was killed, join it so it can finish quiting */
       
    79 			this->m_thread->Join();
       
    80 		}
       
    81 		/* If we continue, we are the current thread */
       
    82 		s_current = cur;
       
    83 	}
       
    84 
       
    85 	/* virtual */ void Exit()
       
    86 	{
       
    87 		/* Kill off our thread */
       
    88 		this->m_kill = true;
       
    89 		this->m_thread->Exit();
       
    90 	}
       
    91 
       
    92 	/* virtual */ bool IsRunning()
       
    93 	{
       
    94 		if (this->m_thread == NULL) return false;
       
    95 		return this->m_thread->IsRunning();
       
    96 	}
       
    97 
       
    98 	/* virtual */ void *GetFiberData()
       
    99 	{
       
   100 		return this->m_param;
       
   101 	}
       
   102 
       
   103 	static Fiber_Thread *GetCurrentFiber()
       
   104 	{
       
   105 		return s_current;
       
   106 	}
       
   107 
       
   108 private:
       
   109 	/**
       
   110 	 * First function which is called within the fiber.
       
   111 	 */
       
   112 	static void * CDECL stFiberProc(void *fiber)
       
   113 	{
       
   114 		Fiber_Thread *cur = (Fiber_Thread *)fiber;
       
   115 		/* Now suspend the thread until we get SwitchToFiber() for the first time */
       
   116 		cur->m_sem->Wait();
       
   117 		/* If we continue, we are the current thread */
       
   118 		s_current = cur;
       
   119 
       
   120 		try {
       
   121 			cur->m_proc(cur->m_param);
       
   122 		} catch (...) {
       
   123 			/* Unlock the main thread */
       
   124 			s_main->m_sem->Set();
       
   125 			throw;
       
   126 		}
       
   127 
       
   128 		return NULL;
       
   129 	}
       
   130 };
       
   131 
       
   132 /* Initialize the static member of Fiber_Thread */
       
   133 /* static */ Fiber_Thread *Fiber_Thread::s_current = NULL;
       
   134 /* static */ Fiber_Thread *Fiber_Thread::s_main = NULL;
       
   135 
       
   136 #ifndef WIN32
       
   137 
       
   138 /* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
       
   139 {
       
   140 	return new Fiber_Thread(proc, param);
       
   141 }
       
   142 
       
   143 /* static */ Fiber *Fiber::AttachCurrent(void *param)
       
   144 {
       
   145 	return new Fiber_Thread(param);
       
   146 }
       
   147 
       
   148 /* static */ void *Fiber::GetCurrentFiberData()
       
   149 {
       
   150 	return Fiber_Thread::GetCurrentFiber()->GetFiberData();
       
   151 }
       
   152 
       
   153 #endif /* WIN32 */