(svn r12538) [NoAI] -Codechange: introducing fiber.hpp, a class to have fibers in your application via either Windows Fibers, or via thread.h noai
authortruebrain
Wed, 02 Apr 2008 10:55:28 +0000
branchnoai
changeset 9859 81621c6ba0e9
parent 9858 b385c3ee0926
child 9860 4f554e7b1985
(svn r12538) [NoAI] -Codechange: introducing fiber.hpp, a class to have fibers in your application via either Windows Fibers, or via thread.h
[NoAI] -Codechange: rewritten ai_threads.cpp, to work with Fiber class. Reduces code duplication, and should fix all the stupid asserts we had with newgames and dying AIs
-NOTE: now my head spins.. 24 hours of working with threads/fibers is bad for health :p Tnx glx for the testing!
projects/generate
projects/generate.vbs
projects/openttd_vs80.vcproj
projects/openttd_vs90.vcproj
source.list
src/ai/ai_threads.cpp
src/fiber.hpp
src/fiber_thread.cpp
src/fiber_win32.cpp
src/genworld.cpp
src/saveload.cpp
src/thread.h
src/thread_pthread.cpp
src/thread_win32.cpp
--- a/projects/generate	Tue Apr 01 13:45:04 2008 +0000
+++ b/projects/generate	Wed Apr 02 10:55:28 2008 +0000
@@ -83,7 +83,7 @@
 			if ($0 == "MSVC"        && "'$os'" != "MSVC")              { next; }
 			if ($0 == "DIRECTMUSIC" && "'$enable_directmusic'" != "1") { next; }
 			if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" )        { next; }
-			if ($0 == "NO_THREADS"  && "'$with_threads'" == "0")       { next; }
+			if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0")       { next; }
 
 			skip += 1;
 
--- a/projects/generate.vbs	Tue Apr 01 13:45:04 2008 +0000
+++ b/projects/generate.vbs	Wed Apr 02 10:55:28 2008 +0000
@@ -72,7 +72,7 @@
 						line = "WIN32" Or _
 						line = "MSVC" Or _
 						line = "DIRECTMUSIC" Or _
-						line = "NO_THREADS" _
+						line = "HAVE_THREAD" _
 					) Then skip = skip + 1
 					deep = deep + 1
 				Case "#"
--- a/projects/openttd_vs80.vcproj	Tue Apr 01 13:45:04 2008 +0000
+++ b/projects/openttd_vs80.vcproj	Wed Apr 02 10:55:28 2008 +0000
@@ -748,6 +748,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\fiber_win32.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\tile_map.cpp"
 				>
 			</File>
@@ -944,6 +948,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\fiber.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\fileio.h"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj	Tue Apr 01 13:45:04 2008 +0000
+++ b/projects/openttd_vs90.vcproj	Wed Apr 02 10:55:28 2008 +0000
@@ -745,6 +745,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\fiber_win32.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\tile_map.cpp"
 				>
 			</File>
@@ -941,6 +945,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\fiber.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\fileio.h"
 				>
 			</File>
--- a/source.list	Tue Apr 01 13:45:04 2008 +0000
+++ b/source.list	Wed Apr 02 10:55:28 2008 +0000
@@ -81,17 +81,19 @@
 tgp.cpp
 #if HAVE_THREAD
 	#if WIN32
-	thread_win32.cpp
+		thread_win32.cpp
+		fiber_win32.cpp
 	#else
 		#if OS2
 			thread_os2.cpp
 		#else
 			thread_pthread.cpp
-		#endif
-	#endif
+		#end
+		fiber_thread.cpp
+	#end
 #else
 	thread_none.cpp
-#endif
+#end
 tile_map.cpp
 #if WIN32
 #else
@@ -156,6 +158,7 @@
 engine_func.h
 engine_type.h
 core/enum_type.hpp
+fiber.hpp
 fileio.h
 fios.h
 fontcache.h
--- a/src/ai/ai_threads.cpp	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/ai/ai_threads.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -7,6 +7,7 @@
 #include "../variables.h"
 #include "../debug.h"
 #include "../thread.h"
+#include "../fiber.hpp"
 #include "../vehicle_func.h"
 #include "../player_func.h"
 #include "ai.h"
@@ -17,136 +18,128 @@
 #include "../misc/countedptr.hpp"
 #include <map>
 
-class AIThread : public SimpleCountedObject {
-public:
-	/** Different states of the AI thread. */
-	enum ThreadState {
+class AIFiber : public SimpleCountedObject {
+private:
+	typedef std::map<int, CCountedPtr<AIFiber> > Fibers;
+
+	/** Different states of the AI fiber. */
+	enum FiberState {
 		INITIALIZED, ///< The mutex and conditions are initialized
-		STARTING,    ///< The thread is just started
+		STARTING,    ///< The fiber is just started
 		RUNNING,     ///< We are inside the main AI
 		SUSPENDED,   ///< We are suspended (either by sleep or block)
 		STOPPING,    ///< We are being stopped
 		STOPPED,     ///< The main AI has stopped
 	};
 
-	static const int MAIN_THREAD = -1;
-
-protected:
-	typedef std::map<int, CCountedPtr<AIThread> > Threads;
-
-	static Threads s_threads;        ///< collection of active fibers
-
-	int            fiber_id;         ///< id of this fiber (or MAIN_THREAD for the main) - equal to the ID of the current player
-	ThreadState    state;            ///< The current state of the AI
-	int            ticks_to_sleep;   ///< Sleep this many runticks
-	AIController   *controller;      ///< Controller of this AI
-
+public:
 	/**
-	 * Initialize this AI Thread base class for the given controller.
-	 * @param player the player ID of this AI (used as fiber_id)
-	 * @param controller the AI have to run
-	 * @note this constructor is protected. It should be called only by
-	 * subclass (OS specific thread implementation).
+	 * Initialize this AIFiber for the given controller.
+	 * @param player The PlayerID of this AI.
+	 * @param controller The AI we have to run.
 	 */
-protected:
-	AIThread(PlayerID player, AIController *controller)
+	AIFiber(PlayerID player, AIController *controller) :
+		fiber_id(player),
+		state(INITIALIZED),
+		ticks_to_sleep(0),
+		controller(controller),
+		fiber(NULL)
 	{
-		assert(s_threads[player] == NULL);
-		/* Register new thread */
-		s_threads[player] = this;
+		/* The player shouldn't have a fiber yet */
+		assert(s_fibers[player] == NULL);
+		/* Register the new fiber */
+		s_fibers[player] = this;
 
-		/* Ensure that main thread has its wrapper too */
-		if (player != MAIN_THREAD) stFind(MAIN_THREAD);
-
-		this->state = INITIALIZED;
-		this->fiber_id = player;
-		this->ticks_to_sleep = 0;
-		this->controller = controller;
+		/* Ensure that main fiber has its wrapper too */
+		if (player != MAIN_FIBER) {
+			stFind(MAIN_FIBER);
+		} else {
+			this->fiber = Fiber::AttachCurrent(this);
+			assert(this->fiber->IsRunning());
+		}
 	}
 
-public:
-	virtual ~AIThread()
+	~AIFiber()
 	{
-		/* At this point we should be already removed from the thread collection */
-		assert(this->fiber_id == MAIN_THREAD || stFind(this->fiber_id) == NULL);
+		/* Make sure we are not in the active list anymore */
+		assert(this->fiber_id == MAIN_FIBER || stFind(this->fiber_id) == NULL);
+		/* Clean up */
+		delete this->fiber;
 	}
 
 	/**
-	 * Start the AI thread and return once the AI calls Sleep or
-	 *  any other suspending command.
-	 * @note should be called after Initialize, but before any other function.
-	 */
-public:
-	virtual bool Start() = 0;
-
-	/**
-	 * The method that runs in the new Thread.
-	 * @note should be called by the newly spawned thread in Start.
+	 * Start the AI fiber and return once the AI calls Sleep or any other
+	 *  suspending command.
 	 */
-protected:
-	void ThreadProc()
+	bool Start()
 	{
-		assert(this->state == STARTING);
-		this->state = RUNNING;
+		/* Make sure we start fibers from the main fiber */
+		assert(stCurrentFiber() == stFind(MAIN_FIBER));
+		/* We shouldn't have a fiber yet */
+		assert(this->fiber == NULL);
+		/* And we shouldn't be starting the main fiber */
+		assert(fiber_id != MAIN_FIBER);
 
-		/* Run the AI. If this function ever returns, the AI is dead */
-		this->controller->Start();
+		/* Create fiber for this AI */
+		this->fiber = Fiber::New(&stFiberProc, this);
+		if (!this->fiber->IsRunning()) return false;
 
-		if (this->state != STOPPING) {
-			DEBUG(ai, 1, "We've got a suicidal AI for player %d", this->fiber_id);
-			/* The AI stopped on it's own */
-			this->state = STOPPED;
-		} else {
-			this->state = STOPPED;
-		}
+		/* Switch to STARTING mode */
+		this->state = SUSPENDED;
+		this->SwitchToState(STARTING);
+
+		return true;
 	}
 
 	/**
-	 * Suspend this AI.
-	 * @param timeout time to suspend. < 0 means infinite (MultiPlayer only!)
-	 * @note should be called from the AI thread.
+	 * Suspend this AI for a 'timeout' of period.
+	 * @param timeout Time to suspend. < 0 means infinite (MultiPlayer only!)
+	 * @note Only call this from within the fiber you want to execute the function on.
 	 */
-public:
 	void Suspend(int timeout)
 	{
 		/* Should not attempt to suspend main fiber */
-		assert(this->fiber_id != MAIN_THREAD);
+		assert(this->fiber_id != MAIN_FIBER);
 		/* AI fiber should be running */
 		assert(this->state == RUNNING);
 		/* We can only suspend ourself */
-		assert(this->CurrentThread() == this);
+		assert(this->stCurrentFiber() == this);
 
 		this->ticks_to_sleep = timeout;
 
-		/* When AI thread gets suspended, it always switches back to main thread */
-		AIThread *main = stFind(MAIN_THREAD);
-		main->SwitchToThis(RUNNING);
+		/* When AI fiber gets suspended, it always switches back to main fiber */
+		AIFiber *main = stFind(MAIN_FIBER);
+		main->SwitchToState(RUNNING);
 
-		/* The AI is told to die by the main thread */
+		/* The main fiber wants this AI to die */
 		if (this->state == STOPPING) {
+			/* Inform the controller */
 			this->controller->Stop();
-			OnStop();
-			/* XXX -- It might be nice to throw an exception, as it is easier to handle */
-			//throw std::exception();
-			//NOT_REACHED();
 
-			main->SwitchToThis(RUNNING);
+			/* Suspend, and exit */
+			this->state = SUSPENDED;
+			this->Exit();
+
+			/* Here we will never come as... the fiber is dead */
+			assert(false);
+
 			return;
 		}
+
 		assert(this->state == RUNNING);
 	}
 
 	/**
-	 * Set the AI thread to resume at the next call of RunTick.
-	 * @note should NOT be called from the AI thread.
+	 * Set the AI fiber to resume at the next call of RunTick.
+	 * @note Only call this from within the main fiber.
 	 */
-public:
 	void Resume()
 	{
 		/* Should be called from main fiber only */
-		assert(CurrentThread() == stFind(MAIN_THREAD));
+		assert(stCurrentFiber() == stFind(MAIN_FIBER));
 		/* AI fiber should be suspended */
 		assert(this->state == SUSPENDED);
+
 		/* Normally the ticks_to_sleep hangs at -1 for MP. Possible the MP is
 		 * faster then the delay requested by the user. In this case the value
 		 * is lower. To let the normal delay system kick in, we reverse the value
@@ -156,22 +149,20 @@
 	}
 
 	/**
-	 * Let the AI thread run for a while and return when it is done.
-	 * However, when the thread is suspended and the suspend timeout
-	 * has not yet passed, nothing happens except decrementing the
-	 * before mentioned timeout.
-	 * @note should NOT be called from the AI thread.
+	 * Let the AI fiber run for a while and return when it is done.
+	 *  However, when the fiber is suspended and the suspend timeout has not yet
+	 *  passed, nothing happens except decrementing the before mentioned timeout.
+	 * @note Only call this from within the main fiber.
 	 */
-public:
 	void RunTick()
 	{
 		/* If we already stopped, don't do anything */
 		if (this->state == STOPPED) return;
 
 		/* Should be called from main fiber only */
-		assert(CurrentThread() == stFind(MAIN_THREAD));
+		assert(stCurrentFiber() == stFind(MAIN_FIBER));
 		/* Only AI fibers should be resumed this way */
-		assert(this != stFind(MAIN_THREAD));
+		assert(this != stFind(MAIN_FIBER));
 		/* AI fiber should be still suspended */
 		assert(this->state == SUSPENDED);
 
@@ -186,664 +177,182 @@
 		if (this->ticks_to_sleep < 0)   return; // We have to wait infinitely
 		if (--this->ticks_to_sleep > 0) return; // We have to wait a little longer
 
-		/* Make the thread running again */
-		this->SwitchToThis(RUNNING);
-	}
-
-	/**
-	 * Stop the AI thread and wait till it is stopped.
-	 * @note should NOT be called from the AI thread.
-	 */
-public:
-	virtual void Stop() = 0;
-
-	/**
-	 * Called before the AI thread finishes. Should wakeup the main thread.
-	 */
-public:
-	virtual void OnStop() {};
-
-	/**
-	 * Called in the context of thread that wants to yield execution and switch
-	 *  to 'this' thread. One of those threads should be always the main thread
-	 *  (fiber_id == MAIN_THREAD).
-	 */
-public:
-	virtual void SwitchToThis(ThreadState new_state) = 0;
-
-	/**
-	 * Find and return the thread object by its 'id' (player_id or MAIN_THREAD).
-	 *  Returns NULL if such thread object doesn't exist. If
-	 *  (fiber_id == MAIN_THREAD) and the thread object with this id doesn't
-	 *  exist, the new one is created and attached to the current (main) thread.
-	 */
-public:
-	static AIThread *stFind(int fiber_id)
-	{
-		Threads::iterator it = s_threads.find(fiber_id);
-		if (it == s_threads.end()) {
-			if (fiber_id != MAIN_THREAD) return NULL;
-			/* main thread doesn't have its own thread object, create it */
-			return stNew((PlayerID)MAIN_THREAD, NULL);
-		}
-		return (*it).second;
-	}
-
-	/**
-	 * Remove thread object from the collection by its 'id' and destroy it.
-	 */
-public:
-	static void stRelease(int fiber_id)
-	{
-		Threads::iterator it = s_threads.find(fiber_id);
-		if (it != s_threads.end()) s_threads.erase(it);
-	}
-
-	/**
-	 * Find the thread object that belongs to the currently running thread (caller).
-	 */
-public:
-	static AIThread *stCurrentThread()
-	{
-		AIThread *main = stFind(MAIN_THREAD);
-		AIThread *cur = main->CurrentThread();
-		return cur;
+		/* Make the fiber running again */
+		this->SwitchToState(RUNNING);
 	}
 
 	/**
-	 * Find the thread object that belongs to the currently running thread (caller).
-	 */
-public:
-	virtual AIThread *CurrentThread() = 0;
-
-	/**
-	 * Create new AI thread object for given player and add it into thread collection.
+	 * Try to stop the AI, and mark it as such. You can cleanup the AI after
+	 *  this if you like; it won't be become active for sure.
+	 * @note There is no guarantee the fiber dies or anything, we just promise
+	 *  it won't be called anymore.
+	 * @note Only call this from within the main fiber.
 	 */
-public:
-	static AIThread *stNew(PlayerID player, AIController *controller);
-};
-
-/**
- * Collection of all AI Thread objects.
- */
-/* static */ AIThread::Threads AIThread::s_threads;
-
-/**
- * AI thread implementation using Win32 thread API. This should be used only on Win95
- * where Fiber API is not supported. Main OTTD thread has assigned the first object
- * in collection (AIThread::s_threads[MAIN_THREAD]). Other threads created by this main
- * thread have assigned higher slots [PlayerID]. This implementation is supposed to emulate
- * Win32 fibers using normal Win32 threads. Synchronisation is done using simple event
- * object (kind of bi-state semaphore gate - 0/1 - which is reset to 0 when thread passes
- * the wait function and must be set back to 1 in order to fire another thread).
- * Each thread from the collection (except one) is wating on its own event object. So the
- * thread that wants to yeald execution must set the event object of the target thread
- * and then enter its own wait state.
- */
-class AIThread_MT : public AIThread {
-	static int s_current;     ///< currently executed thread
-
-	AutoPtrT<ThreadSemaphore> evt_go;       ///< Win32 event handle that signals the thread can go
-	ThreadState              next_state;   ///< Next state after wakeup
-	AutoPtrT<ThreadObject>   thr;          ///< Thread Object associated with this AI thread
-
-	/**
-	 * Initialize this AI Thread Object for the given controller.
-	 * @param player the player ID of this AI (used as fiber_id) or MAIN_THREAD if attaching to the main game thread
-	 * @param controller the AI have to run
-	 */
-public:
-	AIThread_MT(PlayerID player, AIController *controller)
-		: AIThread(player, controller)
-	{
-		DEBUG(ai, 3, "+AIThread_MT(%d) from thr %d", player, ThreadObject::CurrentId());
-		this->evt_go = ThreadSemaphore::New();
-		this->next_state = STOPPED;
-
-		/* Handle main thread differently. When AIThread::AIThread() calls stFind() the new Thread Object
-		 * is created for the main thread. In this case we will not create new system thread but rather
-		 * attach to the curent one. */
-		if (player == MAIN_THREAD) {
-			/* also main thread needs to know own win32 thread id */
-			this->thr = ThreadObject::AttachCurrent();
-		}
-	}
-
-	/**
-	 * Destructor (AI Thread Object cleanup).
-	 */
-public:
-	/*virtual*/ ~AIThread_MT()
+	void Stop()
 	{
-		DEBUG(ai, 3, "-AIThread_MT(%d) from thr %u", this->fiber_id, ThreadObject::CurrentId());
-
-		/* Flush stdout and stderr, as killing the thread doesn't allow the thread
-		 *  to do that (in case there still is something to print) */
-		fflush(stdout);
-		fflush(stderr);
-
-		this->evt_go.Detach();
-	}
-
-	/**
-	 * Implementation specific Start() routine.
-	 * @see AIThread::Start()
-	 */
-public:
-	virtual bool Start()
-	{
-		AIThread_MT *cur = stCurrentFiber();
-		assert(cur != this); // target fiber is not active already
-		assert(fiber_id != MAIN_THREAD); // main fiber can't be started this way
-
-		cur->state = SUSPENDED;
-		this->state = SUSPENDED;
-		this->next_state = STARTING;
-		this->thr = ThreadObject::New(&stThreadProc, this);
-		cur->EnterWaitState();
-
-		return true;
-	}
-
-	/**
-	 * Function that is started as process of the new AI thread (fiber).
-	 * @param fiber AIThread_Fiber* to the fiber that starts
-	 */
-protected:
-	static void CDECL *stThreadProc(void *thr)
-	{
-		AIThread_MT *cur = (AIThread_MT*)thr;
-		cur->FiberProc();
-		return NULL;
-	}
-
-	/**
-	 * The method that runs in the context of new thread (virtual fiber) when started.
-	 */
-protected:
-	void FiberProc()
-	{
-		try
-		{
-			s_current = this->fiber_id;
-			this->state = this->next_state;
-			AIThread::ThreadProc();
-		}
-		catch (std::exception &e)
-		{
-			DEBUG(ai, 0, "%s", e.what());
-		}
-		DEBUG(ai, 3, "thread %d finished", this->fiber_id);
-
-		/* Tell the main thread that we are stopping */
-		this->OnStop();
-	}
-
-	/**
-	 * Implementation specific way how to stop execution of the AI thread.
-	 * @see AIThread::Stop()
-	 */
-public:
-	/*virtual*/ void Stop()
-	{
+		/* Should be called from main fiber only */
+		assert(stCurrentFiber() == stFind(MAIN_FIBER));
 		/* If we already stopped, don't do anything */
 		if (this->state == STOPPED) return;
 
-		AIThread_MT *cur = stCurrentFiber();
-		/* The AI stopping itself */
-		if (cur == this) {
-			/* must be AI fiber */
-			assert(this->fiber_id != MAIN_THREAD);
+		/* Trigger a STOPPING round */
+		assert(this->state == SUSPENDED);
+		this->SwitchToState(STOPPING);
+		assert(this->state == SUSPENDED);
 
-			DEBUG(ai, 3, "this->OnStop(%d) from thr %d", this->fiber_id, ThreadObject::CurrentId());
-			this->state = STOPPED;
-			this->controller->Stop();
-			//throw std::exception();
-			//NOT_REACHED();
-			return;
-		}
-
-		assert(cur->fiber_id == MAIN_THREAD);
-		assert(this->state == SUSPENDED);
-		this->SwitchToThis(STOPPING);
-		assert(this->state == SUSPENDED);
+		/* Mark the fiber as STOPPED */
 		this->state = STOPPED;
 	}
 
 	/**
-	 * This routine should notify main thread that AI thread finished (stopped
-	 * forever).
+	 * Find and return the fiber object by its 'id' (player_id or MAIN_FIBER).
+	 *  Returns NULL if such fiber object doesn't exist. If
+	 *  (fiber_id == MAIN_FIBER) and the fiber object with this id doesn't
+	 *  exist, the new one is created and attached to the current (main) fiber.
 	 */
-protected:
-	/*virtual*/ void OnStop()
+	static AIFiber *stFind(int fiber_id)
 	{
-		AIThread_MT *main = (AIThread_MT*)stFind(MAIN_THREAD);
-		main->evt_go->Set();
-	}
-
-	/**
-	 * Implementation specific way how to yield execution to the other thread (virtual fiber).
-	 * @see AIThread::SwitchToThis()
-	 */
-protected:
-	void SwitchToThis(ThreadState new_state)
-	{
-		AIThread_MT *cur = stCurrentFiber();
-		assert(cur != this); // target fiber is not active already
-		assert(this->state == SUSPENDED); // target fiber is in proper state
-		assert(this->thr->IsRunning() || this->fiber_id == MAIN_THREAD); // target fiber is created
-
-		cur->state = SUSPENDED;
-		this->next_state = new_state;
+		Fibers::iterator it = s_fibers.find(fiber_id);
+		if (it != s_fibers.end()) return (*it).second;
+		if (fiber_id != MAIN_FIBER) return NULL;
 
-		{
-			/* Protect the AI Thread Object against sudden death in the case when
-			 * AI decides to stop itself by calling AI_StopPlayer(). Technically there
-			 * is no problem deleting the the AI Thread Object from its thread, but for
-			 * the code robustness there is assert(m_attached || !IsRunning()); to avoid
-			 * that. */
-			CCountedPtr<AIThread> protect_this = this;
-			this->evt_go->Set();
-			cur->EnterWaitState();
-		} // end of 'protection area'
-	}
-
-	/**
-	 * Wait for the 'GO' signal. This way all thread except one are waiting on their own
-	 * event object in order to emulate cooperative multithreading (fibers).
-	 */
-protected:
-	void EnterWaitState()
-	{
-		assert(this->thr->IsCurrent()); // can wait on own event only
-		this->evt_go->Wait();
-		s_current = this->fiber_id;
-		assert(this->state == SUSPENDED);
-		this->state = this->next_state;
-		assert(this->state != SUSPENDED);
-	}
-
-	/**
-	 * Ugly way how to get AI Thread object that belongs to the currently executed
-	 * (calling) thread.
-	 * @todo consider using TLS API or thread map to make it less ugly
-	 */
-protected:
-	AIThread_MT* stCurrentFiber()
-	{
-		AIThread_MT *cur = (AIThread_MT*)stFind(s_current);
-		assert(cur != NULL);
-		assert(cur->thr->IsCurrent());
-		return cur;
+		/* Main fiber doesn't have its own fiber object, create it */
+		return new AIFiber((PlayerID)MAIN_FIBER, NULL);
 	}
 
 	/**
-	 * Ugly way how to provide stCurrentFiber() functionality for the base class.
+	 * Remove fiber object from the collection by its 'id' and destroy it.
 	 */
-protected:
-	/*virtual*/ AIThread *CurrentThread()
+	static void stRelease(int fiber_id)
 	{
-		return stCurrentFiber();
-	}
-};
-
-/**
- * Ugly way how to get AI Thread object that belongs to the currently executed
- * (calling) thread.
- * @todo consider using TLS API or thread map to make it less ugly
- */
- /* static */ int AIThread_MT::s_current = AIThread::MAIN_THREAD;
-
-#ifdef _WIN32
-
-#include <windows.h>
-#include <process.h>
-
-/**
- * AI thread implementation using native Win32 fiber API. This should be preferred
- * way for most of Win32 platforms - all except Win95 (this API was introduced on Win98).
- * All fibers share the same Win32 thread but each fiber has its own stack and context.
- * They are not preempted, cannot run in parallel and they must cooperatively switch
- * (yield execution from one to another) in order to execute them all.
- * One fiber has id == MAIN_THREAD. This fiber is main (belongs to the main OTTD thread).
- * The main fiber is created using ConvertThreadToFiber() API so then it can create and
- * execute other fibers. Fiber API allows to provide one void* as fiber data. We use it
- * to hold pointer to the AI thread object (AIThread_Fiber*) it is related to and
- * which controls the fiber execution state.
- *
- * This Win32 specific implementation can be made more generic using libpth on unix.
- */
-class AIThread_Fiber : public AIThread {
-	DWORD  id_thr;            ///< Win32 thread id (used for assert only)
-	LPVOID fiber;             ///< Win32 fiber
-
-public:
-	/**
-	 * Initialize this AI Thread Object for the given controller.
-	 * @param player the player ID of this AI (used as fiber_id)
-	 * @param controller the AI have to run
-	 */
-	AIThread_Fiber(PlayerID player, AIController *controller)
-		: AIThread(player, controller)
-	{
-		this->id_thr = GetCurrentThreadId();
-		this->fiber = NULL;
-		if (player == MAIN_THREAD) {
-			this->ConvertThreadToFiber();
-			assert(this->fiber != NULL);
-		}
-	}
-
-	/**
-	 * Destructor (AI Thread Object cleanup).
-	 */
-public:
-	/*virtual*/ ~AIThread_Fiber()
-	{
-		if (this->fiber_id == MAIN_THREAD) {
-			this->ConvertFiberToThread();
-		} else {
-			this->DeleteFiber();
-		}
+		Fibers::iterator it = s_fibers.find(fiber_id);
+		if (it != s_fibers.end()) s_fibers.erase(it);
 	}
 
 	/**
-	 * Fiber specific Start() routine.
-	 * @see AIThread::Start()
+	 * Find the fiber object that belongs to the currently running fiber (caller).
 	 */
-public:
-	virtual bool Start()
-	{
-		assert(stCurrentFiber() != this); // target fiber is not active already
-		assert(this->fiber == NULL); // not yet started
-		assert(fiber_id != MAIN_THREAD); // main fiber can't be started this way
-
-		/* create fiber for this AI thread */
-		this->CreateFiber();
-		if (this->fiber == NULL) return false; // unable to create fiber
-
-		/* Set initial target state and switch to the target thread. This will start
-		 * the other fiber execution by calling its FiberProc(). */
-		this->state = SUSPENDED; // initial state after creation going to wake up soon
-		this->SwitchToThis(STARTING);
-
-		return true; // indicate success
-	}
-
-	/**
-	 * Fiber specific way how to stop execution of the AI thread.
-	 * @see AIThread::Stop()
-	 */
-public:
-	virtual void Stop()
+	static AIFiber *stCurrentFiber()
 	{
-		/* If we already stopped, don't do anything */
-		if (this->state == STOPPED) return;
-
-		AIThread_Fiber *cur = stCurrentFiber();
-		/* The AI stopping itself? */
-		if (cur == this) {
-			/* Yes, stopping itself. Must be AI fiber */
-			assert(this->fiber_id != MAIN_THREAD);
-
-			this->state = STOPPED;
-			this->controller->Stop();
-			//throw std::exception();
-			//NOT_REACHED();
-			return;
-		}
-
-		/* Main thread (fiber) stopping AI thread */
-		assert(cur->fiber_id == MAIN_THREAD);
-		assert(this->state == SUSPENDED);
-		this->SwitchToThis(STOPPING);
-		assert(this->state == SUSPENDED);
-		this->state = STOPPED;
-
-		this->DeleteFiber();
-	}
-
-	/**
-	 * Fiber specific way how to yield execution to the other fiber.
-	 * @see AIThread::SwitchToThis()
-	 */
-public:
-	void SwitchToThis(ThreadState new_state)
-	{
-		assert(stCurrentFiber() != this); // target fiber is not active already
-		assert(this->state == SUSPENDED); // target fiber is in proper state
-		assert(this->fiber != NULL); // target fiber is created
-
-		stCurrentFiber()->state = SUSPENDED;
-
-		{
-			/* Protect 'this' so it can't be deleted inside SwitchToFiber().
-			 * It could happen if AI decides to stop itself by calling AI_StopPlayer().
-			 * The problem is that AI Thread Object destructor calls DeleteFiber(). There
-			 * is built-in limitation that you can't call DeleteFiber() to delete
-			 * the current (running) fiber. If you do so, the thread exits and whole
-			 * application ends. */
-			CCountedPtr<AIThread> protect_this = this;
-			this->state = new_state;
-			this->SwitchToFiber();
-			assert(this->state == SUSPENDED);
-		} // end of 'protection area'
-
-		stCurrentFiber()->state = RUNNING;
-	}
-
-	/**
-	 * Get AI thread instance of the current (calling) fiber.
-	 */
-public:
-	AIThread_Fiber* stCurrentFiber()
-	{
-		AIThread_Fiber *cur = (AIThread_Fiber*)::GetFiberData();
+		AIFiber *cur = (AIFiber *)Fiber::GetCurrentFiberData();
 		assert(cur != NULL);
 		return cur;
 	}
 
+private:
 	/**
-	 * Ugly way how to provide stCurrentFiber() functionality for the base class.
+	 * Switch the state of a fiber. It becomes active and executed until it
+	 *  changes the state. The current active fiber becomes SUSPENDED.
+	 * @note Only call this from an other fiber.
 	 */
-public:
-	/* virtual */ AIThread *CurrentThread()
+	void SwitchToState(FiberState new_state)
 	{
-		return stCurrentFiber();
+		/* You can't switch the state of an already active fiber */
+		assert(stCurrentFiber() != this);
+		/* The fiber should be suspended */
+		assert(this->state == SUSPENDED);
+		/* And there should be an active fiber on it */
+		assert(this->fiber != NULL);
+
+		/* Suspend the fiber */
+		stCurrentFiber()->state = SUSPENDED;
+
+		/* Switch to new state, activate fiber, and check if we are suspended again */
+		this->state = new_state;
+		this->fiber->SwitchToFiber();
+		assert(this->state == SUSPENDED);
 	}
 
+	/**
+	 * The method that runs in the new Fiber. Automaticly called when the Fiber becomes active.
+	 */
+	void FiberProc()
+	{
+		/* We should be starting */
+		assert(this->state == STARTING);
+		/* We should be the active thread */
+		assert(stCurrentFiber() == this);
+
+		/* Switch to running */
+		this->state = RUNNING;
+
+		/* Start up the AI (this should be an infinite loop) */
+		this->controller->Start();
+
+		/* If we come here, the AI exited because it wanted to */
+		DEBUG(ai, 1, "We've got a suicidal AI for player %d", this->fiber_id);
+
+		/* Wait until we are killed nicely by the game */
+		AIFiber *main = stFind(MAIN_FIBER);
+		while (this->state != STOPPING) {
+			main->SwitchToState(RUNNING);
+		}
+
+		/* Suspend, and exit */
+		this->state = SUSPENDED;
+		this->Exit();
+
+		/* Here we will never come as... the fiber is dead */
+		assert(false);
+	}
 
 	/**
-	 * Function that is started as process of the new AI thread (fiber).
-	 * @param fiber AIThread_Fiber* to the fiber that starts
+	 * Function that is started as process of the new AI fiber.
 	 */
-protected:
-	static VOID CALLBACK stFiberProc(LPVOID fiber)
+	static void CDECL stFiberProc(void *fiber)
 	{
-		AIThread_Fiber *cur = (AIThread_Fiber*)fiber;
+		AIFiber *cur = (AIFiber *)fiber;
 		cur->FiberProc();
 	}
 
 	/**
-	 * The method that runs in the context of new Fiber when started.
-	 */
-protected:
-	void FiberProc()
-	{
-		try
-		{
-			AIThread::ThreadProc();
-		}
-		catch (std::exception &e)
-		{
-			DEBUG(ai, 0, "%s", e.what());
-		}
-		DEBUG(ai, 3, "fiber %d finished", this->fiber_id);
-		stFind(MAIN_THREAD)->SwitchToThis(RUNNING);
-	}
-
-	/**
-	 * Simple wrapper of the LoadLibrary() and GetProcAddress() APIs that returns
-	 * pointer to API function of the given name. The fiber specific APIs are retrieved
-	 * this way (dynamically) instead of just linking to the kernel32.dll statically.
-	 * Linking them statically would cause OTTD crash on startup due to the unsatisfied
-	 * imports. In our case we just get NULL if function is not there.
-	 */
-protected:
-	static FARPROC stGetProcAddr(const char *name)
-	{
-		static HMODULE hKernel = LoadLibraryA("kernel32.dll");
-		return GetProcAddress(hKernel, name);
-	}
-
-	/**
-	 * Dynamic wrapper of ConvertThreadToFiber() Win32 API function.
-	 * @see stGetProcAddr
+	 * Exit a running fiber.
+	 * @note Only call this from within the fiber you want to execute the function on.
 	 */
-protected:
-	void ConvertThreadToFiber()
-	{
-		assert(this->fiber_id == MAIN_THREAD);
-		typedef LPVOID (WINAPI *FnConvertThreadToFiber)(LPVOID lpParameter);
-		static FnConvertThreadToFiber fnConvertThreadToFiber = (FnConvertThreadToFiber)stGetProcAddr("ConvertThreadToFiber");
-		assert(fnConvertThreadToFiber != NULL);
-		this->fiber = fnConvertThreadToFiber(this);
-	}
-
-	/**
-	 * Dynamic wrapper of CreateFiber() Win32 API function.
-	 * @see stGetProcAddr
-	 */
-protected:
-	void CreateFiber()
+	void Exit()
 	{
-		assert(this->fiber_id != MAIN_THREAD);
-		typedef LPVOID (WINAPI *FnCreateFiber)(SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter);
-		static FnCreateFiber fnCreateFiber = (FnCreateFiber)stGetProcAddr("CreateFiber");
-		assert(fnCreateFiber != NULL);
-		this->fiber = fnCreateFiber(0, &stFiberProc, this);
-	}
+		/* We can only exit if we are the thread */
+		assert(stCurrentFiber() == this);
+		/* We can never exit the main fiber */
+		assert(fiber_id != MAIN_FIBER);
 
-	/**
-	 * Dynamic wrapper of DeleteFiber() Win32 API function.
-	 * @see stGetProcAddr
-	 */
-protected:
-	void DeleteFiber()
-	{
-		assert(this->fiber_id != MAIN_THREAD);
-		assert(this != stCurrentFiber());
-		typedef VOID (WINAPI * FnDeleteFiber)(LPVOID lpFiber);
-		static FnDeleteFiber fnDeleteFiber = (FnDeleteFiber)stGetProcAddr("DeleteFiber");
-		assert(fnDeleteFiber != NULL);
-		fnDeleteFiber(this->fiber);
-		this->fiber = NULL;
+		this->fiber->Exit();
 	}
 
-	/**
-	 * Dynamic wrapper of ConvertFiberToThread() Win32 API function.
-	 * @see stGetProcAddr
-	 */
-protected:
-	void ConvertFiberToThread()
-	{
-		assert(this->fiber_id == MAIN_THREAD);
-		typedef BOOL (WINAPI *FnConvertFiberToThread)();
-		static FnConvertFiberToThread fnConvertFiberToThread = (FnConvertFiberToThread)stGetProcAddr("ConvertFiberToThread");
-		assert(fnConvertFiberToThread != NULL);
-		fnConvertFiberToThread();
-		this->fiber = NULL;
-	}
+	static Fibers s_fibers;          ///< Collection of active fibers.
+	static const int MAIN_FIBER = -1;
 
-	/**
-	 * Dynamic wrapper of SwitchToFiber() Win32 API function.
-	 * @see stGetProcAddr
-	 */
-protected:
-	void SwitchToFiber()
-	{
-		assert(this->fiber != NULL);
-		typedef VOID (WINAPI *FnSwitchToFiber)(LPVOID fiber);
-		static FnSwitchToFiber fnSwitchToFiber = (FnSwitchToFiber)stGetProcAddr("SwitchToFiber");
-		assert(fnSwitchToFiber != NULL);
-		fnSwitchToFiber(this->fiber);
-	}
-
-	/**
-	 * Returns true if Win32 fiber API is supported.
-	 * @see stGetProcAddr
-	 */
-public:
-	static bool IsSupported()
-	{
-		static bool first_run = true;
-		static bool is_supported = false;
-		if (first_run) {
-			first_run = false;
-			static const char *names[] = {
-				"ConvertThreadToFiber",
-				"CreateFiber",
-				"DeleteFiber",
-				"ConvertFiberToThread",
-				"SwitchToFiber"};
-			for (size_t i = 0; i < lengthof(names); i++) {
-				if (stGetProcAddr(names[i]) == NULL) return false;
-			}
-			is_supported = true;
-		}
-		return is_supported;
-	}
+	int            fiber_id;         ///< id of this fiber (or MAIN_FIBER for the main).
+	FiberState     state;            ///< The current state of the AI.
+	int            ticks_to_sleep;   ///< Sleep this many runticks.
+	AIController   *controller;      ///< Controller of this AI.
+	Fiber          *fiber;           ///< Fiber we are connected to.
 };
 
-/**
- * Create, register and return the new AI Thread object. It should choose the best
- * implementation for the current platform.
- */
-/* static */ AIThread *AIThread::stNew(PlayerID player, AIController *controller)
-{
-	if (AIThread_Fiber::IsSupported()) {
-		/* Fibers are supported, use them */
-		return new AIThread_Fiber(player, controller);
-	}
-	/* Fibers are not supported (Win95?) */
-	return new AIThread_MT(player, controller);
-}
-
-#else /*_WIN32*/
-
-/**
- * Create, register and return the new AI Thread object.
- */
-/* static */ AIThread *AIThread::stNew(PlayerID player, AIController *controller)
-{
-	return new AIThread_MT(player, controller);
-}
-
-#endif /*!_WIN32*/
-
+/* static */ AIFiber::Fibers AIFiber::s_fibers;
 
 /**
  * Suspend the AI handler of a player.
  * @param player the player to suspend for
  * @param timeout Time to suspend. < 0 means infinite (MultiPlayer only!)
- * @note This should be called from within the thread running this player!
+ * @note This should be called from within the fiber running this player!
  */
 void AI_SuspendPlayer(PlayerID player, int timeout)
 {
 	DEBUG(ai, 5, "AI_SuspendPlayer(%d, %d) from thr %d", player, timeout, ThreadObject::CurrentId());
-	AIThread *thr = AIThread::stCurrentThread();
+	AIFiber *thr = AIFiber::stCurrentFiber();
 	assert(thr != NULL);
 	thr->Suspend(timeout);
 }
 
 /**
- * Run the thread of an AI player. Return when it is suspended again.
+ * Run the fiber of an AI player. Return when it is suspended again.
  * @param player the player to run this tick for
  */
 void AI_RunTick(PlayerID player)
 {
 	DEBUG(ai, 6, "AI_RunTick(%d) from thr %d", player, ThreadObject::CurrentId());
-	AIThread *thr = AIThread::stFind(player);
+	AIFiber *thr = AIFiber::stFind(player);
 	if (thr == NULL) {
 		DEBUG(ai, 0, "AI_RunTick() called for dead AI player #%d", player);
 		return;
@@ -859,9 +368,9 @@
 void AI_StartPlayer(PlayerID player, AIController *controller)
 {
 	DEBUG(ai, 3, "AI_StartPlayer(%d) from thr %d", player, ThreadObject::CurrentId());
-	AIThread *thr = AIThread::stFind(player);
+	AIFiber *thr = AIFiber::stFind(player);
 	assert(thr == NULL);
-	thr = AIThread::stNew(player, controller);
+	thr = new AIFiber(player, controller);
 	thr->Start();
 }
 
@@ -872,10 +381,10 @@
 void AI_StopPlayer(PlayerID player)
 {
 	DEBUG(ai, 3, "AI_StopPlayer(%d) from thr %d", player, ThreadObject::CurrentId());
-	AIThread *thr = AIThread::stFind(player);
+	AIFiber *thr = AIFiber::stFind(player);
 	if (thr == NULL) return;
 	thr->Stop();
-	AIThread::stRelease(player);
+	AIFiber::stRelease(player);
 }
 
 /**
@@ -885,14 +394,14 @@
 void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
 {
 	DEBUG(ai, 6, "CcAI(%d) from thr %d", _current_player, ThreadObject::CurrentId());
-	AIThread *thr = AIThread::stFind(_current_player);
+	AIFiber *thr = AIFiber::stFind(_current_player);
 	assert(thr != NULL);
 	/* Store if we were a success or not */
 	AIObject::SetLastCommandRes(success);
 	/* Store some values inside the AIObject static memory */
 	AIObject::SetNewVehicleID(_new_vehicle_id);
 
-	/* Resume the thread now */
+	/* Resume the fiber now */
 	thr->Resume();
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber.hpp	Wed Apr 02 10:55:28 2008 +0000
@@ -0,0 +1,53 @@
+/* $Id$ */
+
+/** @file fiber.hpp */
+
+#ifndef FIBER_HPP
+#define FIBER_HPP
+
+typedef void (CDECL *FiberFunc)(void *);
+
+class Fiber {
+public:
+	/**
+	 * Switch to this fiber.
+	 */
+	virtual void SwitchToFiber() = 0;
+
+	/**
+	 * Exit a fiber.
+	 */
+	virtual void Exit() = 0;
+
+	/**
+	 * Check if a fiber is running.
+	 */
+	virtual bool IsRunning() = 0;
+
+	/**
+	 * Get the 'param' data of the Fiber.
+	 */
+	virtual void *GetFiberData() = 0;
+
+	/**
+	 * Virtual Destructor to mute warnings.
+	 */
+	virtual ~Fiber() {};
+
+	/**
+	 * Create a new fiber, calling proc(param) when running.
+	 */
+	static Fiber *New(FiberFunc proc, void *param);
+
+	/**
+	 * Attach a current thread to a new fiber.
+	 */
+	static Fiber *AttachCurrent(void *param);
+
+	/**
+	 * Get the 'param' data of the current active Fiber.
+	 */
+	static void *GetCurrentFiberData();
+};
+
+#endif /* FIBER_HPP */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber_thread.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -0,0 +1,153 @@
+/* $Id$ */
+
+/** @file fiber_thread.cpp ThreadObject implementation of Fiber. */
+
+#include "stdafx.h"
+#include "fiber.hpp"
+#include "thread.h"
+#include <stdlib.h>
+
+class Fiber_Thread : public Fiber {
+private:
+	ThreadObject *m_thread;
+	FiberFunc m_proc;
+	void *m_param;
+	bool m_attached;
+	ThreadSemaphore *m_sem;
+	bool m_kill;
+
+	static Fiber_Thread *s_current;
+	static Fiber_Thread *s_main;
+
+public:
+	/**
+	 * Create a ThreadObject fiber and start it, calling proc(param).
+	 */
+	Fiber_Thread(FiberFunc proc, void *param) :
+		m_thread(NULL),
+		m_proc(proc),
+		m_param(param),
+		m_attached(false),
+		m_kill(false)
+	{
+		this->m_sem = ThreadSemaphore::New();
+		/* Create a thread and start stFiberProc */
+		this->m_thread = ThreadObject::New(&stFiberProc, this);
+	}
+
+	/**
+	 * Create a ThreadObject fiber and attach current thread to it.
+	 */
+	Fiber_Thread(void *param) :
+		m_thread(NULL),
+		m_proc(NULL),
+		m_param(param),
+		m_attached(true),
+		m_kill(false)
+	{
+		this->m_sem = ThreadSemaphore::New();
+		/* Attach the current thread to this Fiber */
+		this->m_thread = ThreadObject::AttachCurrent();
+		/* We are the current thread */
+		if (s_current == NULL) s_current = this;
+		if (s_main == NULL) s_main = this;
+	}
+
+	~Fiber_Thread()
+	{
+		/* Remove the thread if needed */
+		if (this->m_thread != NULL) {
+			assert(this->m_attached || !this->m_thread->IsRunning());
+			delete this->m_thread;
+		}
+		/* Remove the semaphore */
+		delete this->m_sem;
+	}
+
+	/* virtual */ void SwitchToFiber()
+	{
+		/* You can't switch to yourself */
+		assert(s_current != this);
+		Fiber_Thread *cur = s_current;
+
+		/* Continue the execution of 'this' Fiber */
+		this->m_sem->Set();
+		/* Hold the execution of the current Fiber */
+		cur->m_sem->Wait();
+		if (this->m_kill) {
+			/* If the thread we switched too was killed, join it so it can finish quiting */
+			this->m_thread->Join();
+		}
+		/* If we continue, we are the current thread */
+		s_current = cur;
+	}
+
+	/* virtual */ void Exit()
+	{
+		/* Kill off our thread */
+		this->m_kill = true;
+		this->m_thread->Exit();
+	}
+
+	/* virtual */ bool IsRunning()
+	{
+		if (this->m_thread == NULL) return false;
+		return this->m_thread->IsRunning();
+	}
+
+	/* virtual */ void *GetFiberData()
+	{
+		return this->m_param;
+	}
+
+	static Fiber_Thread *GetCurrentFiber()
+	{
+		return s_current;
+	}
+
+private:
+	/**
+	 * First function which is called within the fiber.
+	 */
+	static void * CDECL stFiberProc(void *fiber)
+	{
+		Fiber_Thread *cur = (Fiber_Thread *)fiber;
+		/* Now suspend the thread until we get SwitchToFiber() for the first time */
+		cur->m_sem->Wait();
+		/* If we continue, we are the current thread */
+		s_current = cur;
+
+		try {
+			cur->m_proc(cur->m_param);
+		} catch (...) {
+			/* Unlock the main thread */
+			s_main->m_sem->Set();
+			throw;
+		}
+
+		return NULL;
+	}
+};
+
+/* Initialize the static member of Fiber_Thread */
+/* static */ Fiber_Thread *Fiber_Thread::s_current = NULL;
+/* static */ Fiber_Thread *Fiber_Thread::s_main = NULL;
+
+#ifndef WIN32
+
+/* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
+{
+	return new Fiber_Thread(proc, param);
+}
+
+/* static */ Fiber *Fiber::AttachCurrent(void *param)
+{
+	return new Fiber_Thread(param);
+}
+
+/* static */ void *Fiber::GetCurrentFiberData()
+{
+	return Fiber_Thread::GetCurrentFiber()->GetFiberData();
+}
+
+#endif /* WIN32 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/fiber_win32.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -0,0 +1,206 @@
+/* $Id$ */
+
+/** @file fiber_win32.cpp Win32 implementation of Fiber. */
+
+#include "stdafx.h"
+#include "fiber.hpp"
+#include <stdlib.h>
+#include <windows.h>
+#include <process.h>
+
+class Fiber_Win32 : public Fiber {
+private:
+	LPVOID m_fiber;
+	FiberFunc m_proc;
+	void *m_param;
+	bool m_attached;
+
+	static Fiber_Win32 *s_main;
+
+public:
+	/**
+	 * Create a win32 fiber and start it, calling proc(param).
+	 */
+	Fiber_Win32(FiberFunc proc, void *param) :
+		m_fiber(NULL),
+		m_proc(proc),
+		m_param(param),
+		m_attached(false)
+	{
+		CreateFiber();
+	}
+
+	/**
+	 * Create a win32 fiber and attach current thread to it.
+	 */
+	Fiber_Win32(void *param) :
+		m_fiber(NULL),
+		m_proc(NULL),
+		m_param(param),
+		m_attached(true)
+	{
+		ConvertThreadToFiber();
+		if (s_main == NULL) s_main = this;
+	}
+
+	/* virtual */ ~Fiber_Win32()
+	{
+		if (this->m_fiber != NULL) {
+			if (this->m_attached) {
+				this->ConvertFiberToThread();
+			} else {
+				this->DeleteFiber();
+			}
+		}
+	}
+
+	/* virtual */ void SwitchToFiber()
+	{
+		typedef VOID (WINAPI *FnSwitchToFiber)(LPVOID fiber);
+
+		static FnSwitchToFiber fnSwitchToFiber = (FnSwitchToFiber)stGetProcAddr("SwitchToFiber");
+		assert(fnSwitchToFiber != NULL);
+
+		fnSwitchToFiber(this->m_fiber);
+	}
+
+	/* virtual */ void Exit()
+	{
+		/* Simply switch back to the main fiber, we kill the fiber sooner or later */
+		s_main->SwitchToFiber();
+	}
+
+	/* virtual */ bool IsRunning()
+	{
+		return this->m_fiber != NULL;
+	}
+
+	/* virtual */ void *GetFiberData()
+	{
+		return this->m_param;
+	}
+
+	/**
+	 * Win95 doesn't have Fiber support. So check if we have Fiber support,
+	 *  and else fall back on Fiber_Thread.
+	 */
+	static bool IsSupported()
+	{
+		static bool first_run = true;
+		static bool is_supported = false;
+
+		if (first_run) {
+			first_run = false;
+			static const char *names[] = {
+				"ConvertThreadToFiber",
+				"CreateFiber",
+				"DeleteFiber",
+				"ConvertFiberToThread",
+				"SwitchToFiber"};
+			for (size_t i = 0; i < lengthof(names); i++) {
+				if (stGetProcAddr(names[i]) == NULL) return false;
+			}
+			is_supported = true;
+		}
+		return is_supported;
+	}
+
+private:
+	/**
+	 * Get a function from kernel32.dll.
+	 * @param name Function to get.
+	 * @return Proc to the function, or NULL when not found.
+	 */
+	static FARPROC stGetProcAddr(const char *name)
+	{
+		static HMODULE hKernel = LoadLibraryA("kernel32.dll");
+		return GetProcAddress(hKernel, name);
+	}
+
+	/**
+	 * First function which is called within the fiber.
+	 */
+	static VOID CALLBACK stFiberProc(LPVOID fiber)
+	{
+		Fiber_Win32 *cur = (Fiber_Win32 *)fiber;
+		cur->m_proc(cur->m_param);
+	}
+
+	/**
+	 * Delete a fiber.
+	 */
+	void DeleteFiber()
+	{
+		typedef VOID (WINAPI *FnDeleteFiber)(LPVOID lpFiber);
+
+		static FnDeleteFiber fnDeleteFiber = (FnDeleteFiber)stGetProcAddr("DeleteFiber");
+		assert(fnDeleteFiber != NULL);
+
+		fnDeleteFiber(this->m_fiber);
+		this->m_fiber = NULL;
+	}
+
+	/**
+	 * Convert a current thread to a fiber.
+	 */
+	void ConvertThreadToFiber()
+	{
+		typedef LPVOID (WINAPI *FnConvertThreadToFiber)(LPVOID lpParameter);
+
+		static FnConvertThreadToFiber fnConvertThreadToFiber = (FnConvertThreadToFiber)stGetProcAddr("ConvertThreadToFiber");
+		assert(fnConvertThreadToFiber != NULL);
+
+		this->m_fiber = fnConvertThreadToFiber(this);
+	}
+
+	/**
+	 * Create a new fiber.
+	 */
+	void CreateFiber()
+	{
+		typedef LPVOID (WINAPI *FnCreateFiber)(SIZE_T dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, LPVOID lpParameter);
+
+		static FnCreateFiber fnCreateFiber = (FnCreateFiber)stGetProcAddr("CreateFiber");
+		assert(fnCreateFiber != NULL);
+
+		this->m_fiber = fnCreateFiber(0, &stFiberProc, this);
+	}
+
+	/**
+	 * Convert a fiber back to a thread.
+	 */
+	void ConvertFiberToThread()
+	{
+		typedef BOOL (WINAPI *FnConvertFiberToThread)();
+
+		static FnConvertFiberToThread fnConvertFiberToThread = (FnConvertFiberToThread)stGetProcAddr("ConvertFiberToThread");
+		assert(fnConvertFiberToThread != NULL);
+
+		fnConvertFiberToThread();
+		this->m_fiber = NULL;
+	}
+};
+
+/* Initialize the static member of Fiber_Win32 */
+/* static */ Fiber_Win32 *Fiber_Win32::s_main = NULL;
+
+/* Include Fiber_Thread, as Win95 needs it */
+#include "fiber_thread.cpp"
+
+/* static */ Fiber *Fiber::New(FiberFunc proc, void *param)
+{
+	if (Fiber_Win32::IsSupported()) return new Fiber_Win32(proc, param);
+	return new Fiber_Thread(proc, param);
+}
+
+/* static */ Fiber *Fiber::AttachCurrent(void *param)
+{
+	if (Fiber_Win32::IsSupported()) return new Fiber_Win32(param);
+	return new Fiber_Thread(param);
+}
+
+/* static */ void *Fiber::GetCurrentFiberData()
+{
+	if (Fiber_Win32::IsSupported()) return ((Fiber *)::GetFiberData())->GetFiberData();
+	return Fiber_Thread::GetCurrentFiber()->GetFiberData();
+}
--- a/src/genworld.cpp	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/genworld.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -84,7 +84,7 @@
 /**
  * The internal, real, generate function.
  */
-static void *_GenerateWorld(void *arg)
+static void * CDECL _GenerateWorld(void *arg)
 {
 	_generating_world = true;
 	if (_network_dedicated) DEBUG(net, 0, "Generating map, please wait...");
--- a/src/saveload.cpp	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/saveload.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -1561,7 +1561,7 @@
 	}
 }
 
-static void* SaveFileToDiskThread(void *arg)
+static void * CDECL SaveFileToDiskThread(void *arg)
 {
 	SaveFileToDisk(true);
 	return NULL;
--- a/src/thread.h	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/thread.h	Wed Apr 02 10:55:28 2008 +0000
@@ -37,6 +37,16 @@
 	virtual bool WaitForStop() = 0;
 
 	/**
+	 * Exit this thread.
+	 */
+	virtual bool Exit() = 0;
+
+	/**
+	 * Join this thread.
+	 */
+	virtual void Join() = 0;
+
+	/**
 	 * Check if this thread is the current active thread.
 	 * @return True if it is the current active thread.
 	 */
--- a/src/thread_pthread.cpp	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/thread_pthread.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -117,6 +117,26 @@
 		return false;
 	}
 
+	/* 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());
+
+		pthread_join(m_thr, NULL);
+		m_thr = 0;
+	}
+
 	/* virtual */ bool IsCurrent()
 	{
 		return pthread_self() == m_thr;
@@ -134,7 +154,7 @@
 	 */
 	static void *stThreadProc(void *thr)
 	{
-		return ((ThreadObject_pthread*)thr)->ThreadProc();
+		return ((ThreadObject_pthread *)thr)->ThreadProc();
 	}
 
 	/**
@@ -150,13 +170,11 @@
 		try {
 			m_proc(m_param);
 		} catch (...) {
-			DEBUG(misc, 0, "Exception in thread %u!", GetId());
 		}
-		/* The thread died, so we are no longer valid */
-		m_thr = 0;
 
 		/* Notify threads waiting for our completion */
 		sem_post(&m_sem_stop);
+
 		return NULL;
 	}
 };
--- a/src/thread_win32.cpp	Tue Apr 01 13:45:04 2008 +0000
+++ b/src/thread_win32.cpp	Wed Apr 02 10:55:28 2008 +0000
@@ -130,6 +130,25 @@
 		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();
@@ -148,7 +167,7 @@
 	 */
 	static uint CALLBACK stThreadProc(void *thr)
 	{
-		return ((ThreadObject_Win32*)thr)->ThreadProc();
+		return ((ThreadObject_Win32 *)thr)->ThreadProc();
 	}
 
 	/**
@@ -160,7 +179,6 @@
 		try {
 			m_proc(m_param);
 		} catch (...) {
-			DEBUG(misc, 0, "Exception in thread %d!", m_id_thr);
 		}
 
 		return 0;