1. rude
  2. love

Commits

Bart van Strien  committed 41c1ec7 Merge

Merge minor into default, next release shall be 0.9.0

  • Participants
  • Parent commits 2445d1b, 730ed5f
  • Branches default

Comments (0)

Files changed (54)

File changes.txt

View file
-LOVE 0.8.1 [Rubber Piggy]
+LOVE 0.9.0 []
 --------------
 
   * Added --fused command line argument, to simulate fusing.
   * Added boolean support to Shader:send.
   * Added support for UTF-8 ImageFonts.
   * Added SoundData:getDuration.
+  * Added new Channels api for love.thread.
+  * Added flags to setMode.
+  * Added support for resizable and borderless windows.
+  * Added resize event.
+  * Added love.math module.
+  * Added a platform-independent (good) random implementation to love.math.
   * OPTIONAL: Added support for GME.
 
   * Fixed crashes with font drawing on some ATI cards.
 
   * Removed love.joystick.open and friends.
   * Removed love.graphics.drawTest.
+  * Removed thread names.
+  * Removed old thread messaging api (see Channels).
+  * Removed love.graphics.quad/triangle.
 
   * Updated allocation for SoundData, it's more efficient and less wasteful.
   * Updated Source:set* functions to default z to 0.

File platform/unix/exclude

View file
 \./modules/native/tcc/libtcc/stab\.h
 \./libraries/luasocket/libluasocket/wsocket\.*
 \./modules/sound/lullaby/FLACDecoder\.*
-\./modules/thread/sdl/*
-\./modules/thread/win32/*
-\./modules/thread/posix/*
 \./love\.cpp

File src/common/Object.h

View file
 	 * Retains the Object, i.e. increases the
 	 * reference count by one.
 	 **/
-	void retain();
+	virtual void retain();
 
 	/**
 	 * Releases one reference to the Object, i.e. decrements the
 	 * reference count by one, and potentially deletes the Object
 	 * if there are no more references.
 	 **/
-	void release();
+	virtual void release();
 
 private:
 
 	// The reference count.
 	int count;
 }; // Object
-
 } // love
 
 #endif // LOVE_OBJECT_H

File src/common/delay.cpp

View file
  **/
 
 #include "delay.h"
+#include <SDL.h>
 
 namespace love
 {
 
 void delay(unsigned int ms)
 {
-#if LOVE_THREADS == LOVE_THREADS_POSIX
-	struct timespec ts1, ts2;
-
-	ts1.tv_sec = ms / 1000;
-	ts1.tv_nsec = (ms % 1000) * 1000000;
-	// FIXME: handle signals
-	nanosleep(&ts1, &ts2);
-#elif LOVE_THREADS == LOVE_THREADS_WIN32
-	Sleep(ms);
-#elif LOVE_THREADS == LOVE_THREADS_SDL
 	SDL_Delay(ms);
-#endif
 }
 
 } // love

File src/common/delay.h

View file
 #ifndef DELAY_H_
 #define DELAY_H_
 
-#include <thread/threads.h>
-
 namespace love
 {
 

File src/common/math.h

File contents unchanged.

File src/common/runtime.cpp

View file
 #include "Object.h"
 #include "Reference.h"
 #include "StringMap.h"
-#include "thread/threads.h"
+#include <thread/threads.h>
 
 // STD
 #include <iostream>
 
 static thread::Mutex *gcmutex = 0;
 void *_gcmutex = 0;
-unsigned int _gcthread = 0;
 /**
  * Called when an object is collected. The object is released
  * once in this function, possibly deleting it.
 {
 	if (!gcmutex)
 	{
-		gcmutex = new thread::Mutex();
+		gcmutex = thread::newMutex();
 		_gcmutex = (void *) gcmutex;
 	}
 	Proxy *p = (Proxy *)lua_touserdata(L, 1);
 	if (p->own)
 	{
 		thread::Lock lock(gcmutex);
-		_gcthread = thread::ThreadBase::threadId();
 		t->release();
 	}
 	return 0;
 	return b;
 }
 
+std::string luax_tostring(lua_State *L, int idx)
+{
+	size_t len;
+	const char *str = lua_tolstring(L, idx, &len);
+	return std::string(str, len);
+}
+
 std::string luax_checkstring(lua_State *L, int idx)
 {
 	size_t len;
 
 	// Thread
 	{"Thread", THREAD_THREAD_ID},
+	{"Channel", THREAD_CHANNEL_ID},
 
 	// The modules themselves. Only add abstracted modules here.
 	{"filesystem", MODULE_FILESYSTEM_ID},

File src/common/runtime.h

View file
  * @param idx The index on the Lua stack.
  * @return Copy of the string at the specified index.
  **/
+std::string luax_tostring(lua_State *L, int idx);
+
+/**
+ * Converts the value at idx to a std::string. It takes care of the string
+ * size and possible embedded nulls.
+ * @param L The Lua state.
+ * @param idx The index on the Lua stack.
+ * @return Copy of the string at the specified index.
+ **/
 std::string luax_checkstring(lua_State *L, int idx);
 
 /**

File src/common/types.h

View file
 
 	// Thread
 	THREAD_THREAD_ID,
+	THREAD_CHANNEL_ID,
 
 	// The modules themselves. Only add abstracted modules here.
 	MODULE_FILESYSTEM_ID,
 
 // Thread.
 const bits THREAD_THREAD_T = (bits(1) << THREAD_THREAD_ID) | OBJECT_T;
+const bits THREAD_CHANNEL_T = (bits(1) << THREAD_CHANNEL_ID) | OBJECT_T;
 
 // Modules.
 const bits MODULE_FILESYSTEM_T = (bits(1) << MODULE_FILESYSTEM_ID) | MODULE_T;

File src/modules/audio/openal/Audio.cpp

View file
 
 #include "sound/Decoder.h"
 
+#include <cstdlib>
+
 namespace love
 {
 namespace audio
 	: pool(pool)
 	, finish(false)
 {
+	mutex = thread::newMutex();
 }
 
-void Audio::PoolThread::main()
+Audio::PoolThread::~PoolThread()
+{
+	delete mutex;
+}
+
+
+void Audio::PoolThread::threadFunction()
 {
 	while (true)
 	{
 	finish = true;
 }
 
-
 Audio::Audio() : distanceModel(DISTANCE_INVERSE_CLAMPED)
 {
 	// Passing zero for default device.

File src/modules/audio/openal/Audio.h

View file
 	// The Pool.
 	Pool *pool;
 
-	class PoolThread: public thread::ThreadBase
+	class PoolThread: public thread::Threadable
 	{
 	protected:
 		Pool *pool;
 		volatile bool finish;
 
 		// finish lock
-		thread::Mutex mutex;
-
-		virtual void main();
+		thread::Mutex *mutex;
 
 	public:
 		PoolThread(Pool *pool);
+		~PoolThread();
 		void setFinish();
+		void threadFunction();
 	};
 
 	PoolThread *poolThread;

File src/modules/audio/openal/Pool.cpp

View file
 	alGenSources(NUM_SOURCES, sources);
 
 	// Create the mutex.
-	mutex = new thread::Mutex();
+	mutex = thread::newMutex();
 
 	if (alGetError() != AL_NO_ERROR)
 		throw love::Exception("Could not generate sources.");

File src/modules/event/Event.cpp

View file
 	return m;
 }
 
+Event::Event()
+{
+	mutex = thread::newMutex();
+}
+
 Event::~Event()
 {
+	delete mutex;
 }
 
 void Event::push(Message *msg)

File src/modules/event/Event.h

View file
 class Event : public Module
 {
 public:
+	Event();
 	virtual ~Event();
 
 	void push(Message *msg);
 	static bool getConstant(love::keyboard::Keyboard::Key in, const char  *&out);
 
 protected:
-	thread::Mutex mutex;
+	thread::Mutex *mutex;
 	std::queue<Message *> queue;
 	static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry buttonEntries[];
 	static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM> buttons;
 	static StringMap<love::keyboard::Keyboard::Key, love::keyboard::Keyboard::KEY_MAX_ENUM>::Entry keyEntries[];
 	static StringMap<love::keyboard::Keyboard::Key, love::keyboard::Keyboard::KEY_MAX_ENUM> keys;
-
 }; // Event
 
 } // event

File src/modules/event/sdl/Event.cpp

View file
 	case SDL_QUIT:
 		msg = new Message("quit");
 		break;
+	case SDL_VIDEORESIZE:
+		arg1 = new Variant((double) e.resize.w);
+		arg2 = new Variant((double) e.resize.h);
+		msg = new Message("resize", arg1, arg2);
+		arg1->release();
+		arg2->release();
+		break;
 	}
 
 	return msg;

File src/modules/graphics/opengl/Graphics.cpp

View file
 #include <algorithm>
 #include <iterator>
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
 		setScissor();
 }
 
-bool Graphics::setMode(int width, int height, bool fullscreen, bool vsync, int fsaa)
+bool Graphics::setMode(int width, int height, WindowFlags *flags)
 {
 	// This operation destroys the OpenGL context, so
 	// we must save the state.
 
 	uninitializeContext();
 
-	bool success = currentWindow->setWindow(width, height, fullscreen, vsync, fsaa);
+	bool success = currentWindow->setWindow(width, height, flags);
+
 	// Regardless of failure, we'll have to set up OpenGL once again.
-
 	width = currentWindow->getWidth();
 	height = currentWindow->getHeight();
 
 	// Okay, setup OpenGL.
-
 	initializeContext();
 
 	// Make sure antialiasing works when set elsewhere
 	return success;
 }
 
-void Graphics::getMode(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const
+void Graphics::getMode(int &width, int &height, WindowFlags &flags) const
 {
-	currentWindow->getWindow(width, height, fullscreen, vsync, fsaa);
+	currentWindow->getWindow(width, height, flags);
 }
 
 bool Graphics::toggleFullscreen()
 {
-	int width, height, fsaa;
-	bool fullscreen, vsync;
-	currentWindow->getWindow(width, height, fullscreen, vsync, fsaa);
-	return setMode(width, height, !fullscreen, vsync, fsaa);
+	int width, height;
+	WindowFlags flags;
+	currentWindow->getWindow(width, height, flags);
+	flags.fullscreen = !flags.fullscreen;
+	return setMode(width, height, &flags);
 }
 
 

File src/modules/graphics/opengl/Graphics.h

View file
 #include "Canvas.h"
 #include "Shader.h"
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
 	 * Sets the current display mode.
 	 * @param width The window width.
 	 * @param height The window height.
-	 * @param fullscreen True if fullscreen, false otherwise.
-	 * @param vsync True if we should wait for vsync, false otherwise.
-	 * @param fsaa Number of full scene anti-aliasing buffer, or 0 for disabled.
+	 * @param flags An optional WindowFlags structure.
 	 **/
-	bool setMode(int width, int height, bool fullscreen, bool vsync, int fsaa);
+	bool setMode(int width, int height, WindowFlags *flags);
 
 	/**
 	 * Gets the current display mode.
 	 * @param width Pointer to an integer for the window width.
 	 * @param height Pointer to an integer for the window height.
-	 * @param fullscreen Pointer to a boolean for the fullscreen status.
-	 * @param vsync Pointer to a boolean for the vsync status.
-	 * @param fsaa Pointer to an integer for the current number of full scene anti-aliasing buffers.
+	 * @param flags A WindowFlags structure.
 	 **/
-	void getMode(int &width, int &height, bool &fullscreen, bool &vsync, int &fsaa) const;
+	void getMode(int &width, int &height, WindowFlags &flags) const;
 
 	/**
 	 * Toggles fullscreen. Note that this also needs to reload the

File src/modules/graphics/opengl/ParticleSystem.cpp

File contents unchanged.

File src/modules/graphics/opengl/wrap_Graphics.cpp

View file
 #include "scripts/graphics.lua.h"
 #include <cassert>
 
+using love::window::WindowFlags;
+
 namespace love
 {
 namespace graphics
 
 static Graphics *instance = 0;
 
+bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultValue)
+{
+	lua_getfield(L, table_index, key);
+
+	bool retval;
+	if (lua_isnoneornil(L, -1))
+		retval = defaultValue;
+	else
+		retval = lua_toboolean(L, -1);
+
+	lua_pop(L, 1);
+	return retval;
+}
+
+int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue)
+{
+	lua_getfield(L, table_index, key);
+
+	int retval;
+	if (!lua_isnumber(L, -1))
+		retval = defaultValue;
+	else
+		retval = lua_tonumber(L, -1);
+
+	lua_pop(L, 1);
+	return retval;
+}
+
 int w_checkMode(lua_State *L)
 {
 	int w = luaL_checkint(L, 1);
 {
 	int w = luaL_checkint(L, 1);
 	int h = luaL_checkint(L, 2);
-	bool fs = luax_optboolean(L, 3, false);
-	bool vsync = luax_optboolean(L, 4, true);
-	int fsaa = luaL_optint(L, 5, 0);
-	luax_pushboolean(L, instance->setMode(w, h, fs, vsync, fsaa));
+	if (lua_isnoneornil(L, 3))
+	{
+		luax_pushboolean(L, instance->setMode(w, h, 0));
+		return 1;
+	}
+
+	luaL_checktype(L, 3, LUA_TTABLE);
+
+	WindowFlags flags;
+
+	flags.fullscreen = luax_boolflag(L, 3, "fullscreen", false);
+	flags.vsync = luax_boolflag(L, 3, "vsync", true);
+	flags.fsaa = luax_intflag(L, 3, "fsaa", 0);
+	flags.resizable = luax_boolflag(L, 3, "resizable", false);
+	flags.borderless = luax_boolflag(L, 3, "borderless", false);
+
+	luax_pushboolean(L, instance->setMode(w, h, &flags));
 	return 1;
 }
 
 int w_getMode(lua_State *L)
 {
-	int w, h, fsaa;
-	bool fs, vsync;
-	instance->getMode(w, h, fs, vsync, fsaa);
+	int w, h;
+	WindowFlags flags;
+	instance->getMode(w, h, flags);
 	lua_pushnumber(L, w);
 	lua_pushnumber(L, h);
-	lua_pushboolean(L, fs);
-	lua_pushboolean(L, vsync);
-	lua_pushnumber(L, fsaa);
-	return 5;
+
+	lua_newtable(L);
+
+	luax_pushboolean(L, flags.fullscreen);
+	lua_setfield(L, -2, "fullscreen");
+
+	luax_pushboolean(L, flags.vsync);
+	lua_setfield(L, -2, "vsync");
+
+	lua_pushnumber(L, flags.fsaa);
+	lua_setfield(L, -2, "fsaa");
+
+	luax_pushboolean(L, flags.resizable);
+	lua_setfield(L, -2, "resizable");
+
+	luax_pushboolean(L, flags.borderless);
+	lua_setfield(L, -2, "borderless");
+
+	return 3;
 }
 
 int w_toggleFullscreen(lua_State *L)
 
 	{ "point", w_point },
 	{ "line", w_line },
-	{ "triangle", w_triangle },
+	//{ "triangle", w_triangle },
 	{ "rectangle", w_rectangle },
-	{ "quad", w_quad },
+	//{ "quad", w_quad },
 	{ "circle", w_circle },
 	{ "arc", w_arc },
 

File src/modules/image/ImageData.cpp

View file
 
 #include "ImageData.h"
 
+#include <stdio.h>
+
 using love::thread::Lock;
 
 namespace love
 namespace image
 {
 
+ImageData::ImageData()
+{
+	mutex = thread::newMutex();
+}
+
+ImageData::~ImageData()
+{
+	delete mutex;
+}
+
 void *ImageData::getData() const
 {
 	return data;

File src/modules/image/ImageData.h

View file
 	// We need to be thread-safe
 	// so we lock when we're accessing our
 	// data
-	Mutex mutex;
+	Mutex *mutex;
 
 public:
 
 		FORMAT_MAX_ENUM
 	};
 
+	ImageData();
+
 	/**
 	 * Destructor.
 	 **/
-	virtual ~ImageData() {};
+	virtual ~ImageData();
 
 	static bool getConstant(const char *in, Format &out);
 	static bool getConstant(Format in, const char  *&out);

File src/modules/image/devil/ImageData.cpp

View file
 
 using love::thread::Lock;
 
-static Mutex devilMutex;
+static Mutex *devilMutex = 0;
 
 namespace love
 {
 
 void ImageData::load(Data *data)
 {
+	if (!devilMutex)
+		devilMutex = thread::newMutex();
+
 	Lock lock(devilMutex);
 	ILuint image;
 	ilGenImages(1, &image);
 
 void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
 {
+	if (!devilMutex)
+		devilMutex = thread::newMutex();
+
 	Lock lock1(devilMutex);
 	Lock lock2(mutex);
 

File src/modules/image/devil/ImageData.h

View file
 	// Implements ImageData.
 	void encode(love::filesystem::File *f, Format format);
 
+	// We need to be thread-safe
+	// so we lock when we're accessing our
+	// data
+	Mutex *mutex;
+
 }; // ImageData
 
 } // devil

File src/modules/thread/Channel.cpp

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "Channel.h"
+#include <map>
+#include <string>
+
+namespace
+{
+union uslong
+{
+	unsigned long u;
+	long i;
+};
+
+// target <= current, but semi-wrapsafe, one wrap, anyway
+inline bool past(unsigned int target, unsigned int current)
+{
+	if (target > current)
+		return false;
+	if (target == current)
+		return true;
+
+	uslong t, c;
+	t.u = target;
+	c.u = current;
+
+	return !(t.i < 0 && c.i > 0);
+}
+}
+
+namespace love
+{
+namespace thread
+{
+static std::map<std::string, Channel *> namedChannels;
+static Mutex *namedChannelMutex;
+
+Channel *Channel::getChannel(const std::string &name)
+{
+	if (!namedChannelMutex)
+		namedChannelMutex = newMutex();
+
+	Lock l(namedChannelMutex);
+	if (!namedChannels.count(name))
+		namedChannels[name] = new Channel(name);
+	else
+		namedChannels[name]->retain();
+
+	return namedChannels[name];
+}
+
+Channel::Channel()
+	: named(false)
+	, sent(0)
+	, received(0)
+{
+	mutex = newMutex();
+	cond = newConditional();
+}
+
+Channel::Channel(const std::string &name)
+	: named(true)
+	, name(name)
+	, sent(0)
+	, received(0)
+{
+	mutex = newMutex();
+	cond = newConditional();
+}
+
+Channel::~Channel()
+{
+	while (!queue.empty())
+	{
+		queue.front()->release();
+		queue.pop();
+	}
+
+	delete mutex;
+	delete cond;
+
+	if (named)
+		namedChannels.erase(name);
+}
+
+unsigned long Channel::push(Variant *var)
+{
+	if (!var)
+		return 0;
+
+	Lock l(mutex);
+	var->retain();
+
+	// Keep a reference to ourselves
+	// if we're non-empty and named.
+	if (named && queue.empty())
+		retain();
+
+	queue.push(var);
+	cond->broadcast();
+
+	return ++sent;
+}
+
+void Channel::supply(Variant *var)
+{
+	if (!var)
+		return;
+
+	mutex->lock();
+	unsigned long id = push(var);
+
+	while (!past(id, received))
+		cond->wait(mutex);
+
+	mutex->unlock();
+}
+
+Variant *Channel::pop()
+{
+	Lock l(mutex);
+	if (queue.empty())
+		return 0;
+
+	Variant *var = queue.front();
+	queue.pop();
+
+	received++;
+	cond->broadcast();
+
+	// Release our reference to ourselves
+	// if we're empty and named.
+	if (named && queue.empty())
+		release();
+
+	return var;
+} // NOTE: Returns a retained Variant
+
+Variant *Channel::demand()
+{
+	Variant *var;
+	mutex->lock();
+	while (!(var = pop()))
+		cond->wait(mutex);
+
+	mutex->unlock();
+	return var;
+}
+
+Variant *Channel::peek()
+{
+	Lock l(mutex);
+	if (queue.empty())
+		return 0;
+
+	Variant *var = queue.front();
+	var->retain();
+	return var;
+}
+
+int Channel::count()
+{
+	Lock l(mutex);
+	return queue.size();
+}
+
+void Channel::clear()
+{
+	Lock l(mutex);
+
+	// We're already empty.
+	if (queue.empty())
+		return;
+
+	while (!queue.empty())
+	{
+		queue.front()->release();
+		queue.pop();
+	}
+
+	// Finish all the supply waits
+	received = sent;
+	cond->broadcast();
+
+	// Once again, release our own
+	// reference if we're named.
+	if (named)
+		release();
+}
+
+void Channel::lockMutex()
+{
+	mutex->lock();
+}
+
+void Channel::unlockMutex()
+{
+	mutex->unlock();
+}
+
+void Channel::retain()
+{
+	if (named)
+		namedChannelMutex->lock();
+
+	Object::retain();
+
+	if (named)
+		namedChannelMutex->unlock();
+}
+
+void Channel::release()
+{
+	if (named)
+		namedChannelMutex->lock();
+
+	Object::release();
+
+	if (named)
+		namedChannelMutex->unlock();
+}
+} // thread
+} // love

File src/modules/thread/Channel.h

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_CHANNEL_H
+#define LOVE_THREAD_CHANNEL_H
+
+// STL
+#include <queue>
+#include <string>
+
+// LOVE
+#include <common/Variant.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class Channel : public love::Object
+{
+// FOR WRAPPER USE ONLY
+friend void retainVariant(Channel *, Variant *);
+friend void releaseVariant(Channel *, Variant *);
+
+public:
+	Channel();
+	~Channel();
+	static Channel *getChannel(const std::string &name);
+
+	unsigned long push(Variant *var);
+	void supply(Variant *var); // blocking push
+	Variant *pop();
+	Variant *demand(); // blocking pop
+	Variant *peek();
+	int count();
+	void clear();
+
+	void retain();
+	void release();
+
+private:
+	Channel(const std::string &name);
+	void lockMutex();
+	void unlockMutex();
+
+	Mutex *mutex;
+	Conditional *cond;
+	std::queue<Variant *> queue;
+	bool named;
+	std::string name;
+
+	unsigned long sent;
+	unsigned long received;
+}; // Channel
+} // thread
+} // love
+
+#endif // LOVE_THREAD_CHANNEL_H

File src/modules/thread/LuaThread.cpp

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "LuaThread.h"
+#include <common/config.h>
+
+#ifdef LOVE_BUILD_STANDALONE
+extern "C" int luaopen_love(lua_State * L);
+#endif // LOVE_BUILD_STANDALONE
+extern "C" int luaopen_love_thread(lua_State *L);
+
+namespace love
+{
+namespace thread
+{
+LuaThread::LuaThread(const std::string &name, love::Data *code)
+	: name(name), code(code)
+{
+	code->retain();
+}
+
+LuaThread::~LuaThread()
+{
+	code->release();
+}
+
+void LuaThread::threadFunction()
+{
+	this->retain();
+	lua_State * L = lua_open();
+	luaL_openlibs(L);
+#ifdef LOVE_BUILD_STANDALONE
+	love::luax_preload(L, luaopen_love, "love");
+	luaopen_love(L);
+#endif // LOVE_BUILD_STANDALONE
+	luaopen_love_thread(L);
+	if (luaL_loadbuffer(L, (const char *) code->getData(), code->getSize(), name.c_str()) != 0)
+		error = luax_tostring(L, -1);
+	else
+		if (lua_pcall(L, 0, 0, 0) != 0)
+			error = luax_tostring(L, -1);
+	lua_close(L);
+	this->release();
+}
+
+const std::string &LuaThread::getError()
+{
+	return error;
+}
+} // thread
+} // love

File src/modules/thread/LuaThread.h

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_LUATHREAD_H
+#define LOVE_THREAD_LUATHREAD_H
+
+// STL
+#include <string>
+
+// LOVE
+#include <common/Object.h>
+#include <common/Data.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class LuaThread : public love::Object, public Threadable
+{
+public:
+	LuaThread(const std::string &name, love::Data *code);
+	~LuaThread();
+	void threadFunction();
+	const std::string &getError();
+
+private:
+	love::Data *code;
+	std::string name;
+	std::string error;
+};
+} // thread
+} // love
+
+#endif // LOVE_THREAD_LUATHREAD_H

File src/modules/thread/Thread.cpp

-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "common/config.h"
-
-#include "Thread.h"
-
-#ifdef LOVE_BUILD_STANDALONE
-extern "C" int luaopen_love(lua_State *L);
-#endif // LOVE_BUILD_STANDALONE
-extern "C" int luaopen_love_thread(lua_State *L);
-
-namespace love
-{
-namespace thread
-{
-
-Thread::ThreadThread::ThreadThread(ThreadData *comm)
-	: comm(comm)
-{
-}
-
-void Thread::ThreadThread::main()
-{
-	lua_State *L = luaL_newstate();
-	luaL_openlibs(L);
-#ifdef LOVE_BUILD_STANDALONE
-	love::luax_preload(L, luaopen_love, "love");
-	luaopen_love(L);
-#endif // LOVE_BUILD_STANDALONE
-	luaopen_love_thread(L);
-	{
-		size_t len;
-		const char *name = comm->getName(&len);
-		lua_pushlstring(L, name, len);
-	}
-	luax_convobj(L, lua_gettop(L), "thread", "getThread");
-	lua_getglobal(L, "love");
-	lua_pushvalue(L, -2);
-	lua_setfield(L, -2, "_curthread");
-	if (luaL_dostring(L, comm->getCode()) == 1)
-	{
-		{
-			Lock lock((Mutex *) comm->mutex);
-			Variant *v = new Variant(lua_tostring(L, -1), lua_strlen(L, -1));
-			comm->setValue("error", v);
-			v->release();
-		}
-		((Conditional *) comm->cond)->broadcast();
-	}
-	lua_close(L);
-}
-
-ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond)
-	: mutex(mutex), cond(cond), len(len)
-{
-	this->name = new char[len+1];
-	memset(this->name, 0, len+1);
-	memcpy(this->name, name, len);
-	if (code)
-	{
-		len = strlen(code);
-		this->code = new char[len+1];
-		memset(this->code, 0, len+1);
-		memcpy(this->code, code, len);
-	}
-	else
-		this->code = 0;
-}
-
-ThreadData::~ThreadData()
-{
-	delete[] name;
-	delete[] code;
-}
-
-const char *ThreadData::getCode()
-{
-	return code;
-}
-
-const char *ThreadData::getName(size_t *len)
-{
-	if (len)
-		 *len = this->len;
-	return name;
-}
-
-Variant *ThreadData::getValue(const std::string &name)
-{
-	if (shared.count(name) == 0)
-		return 0;
-	return shared[name];
-}
-
-void ThreadData::clearValue(const std::string &name)
-{
-	if (shared.count(name) == 0)
-		return;
-	shared[name]->release();
-	shared.erase(name);
-}
-
-void ThreadData::setValue(const std::string &name, Variant *v)
-{
-	if (shared.count(name) != 0)
-		shared[name]->release();
-	v->retain();
-	shared[name] = v;
-}
-
-std::vector<std::string> ThreadData::getKeys()
-{
-	std::vector<std::string> keys;
-	for (std::map<std::string, Variant *>::iterator it = shared.begin(); it != shared.end(); it++)
-	{
-		keys.push_back(it->first);
-	}
-	return keys;
-}
-
-Thread::Thread(love::thread::ThreadModule *module, const std::string &name, love::Data *data)
-	: handle(0), module(module), name(name), isThread(true)
-{
-	module->retain();
-	unsigned int len = data->getSize();
-	this->data = new char[len+1];
-	memset(this->data, 0, len+1);
-	memcpy(this->data, data->getData(), len);
-	mutex = new Mutex();
-	cond = new Conditional();
-	comm = new ThreadData(name.c_str(), name.length(), this->data, mutex, cond);
-}
-
-Thread::Thread(love::thread::ThreadModule *module, const std::string &name)
-	: handle(0), module(module), name(name), data(0), isThread(false)
-{
-	module->retain();
-	mutex = new Mutex();
-	cond = new Conditional();
-	comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond);
-}
-
-Thread::~Thread()
-{
-	if (data)
-		delete[] data;
-	delete comm;
-	module->unregister(name);
-	delete mutex;
-	delete cond;
-	module->release();
-}
-
-void Thread::start()
-{
-	if (!handle && isThread)
-	{
-		handle = new ThreadThread(comm);
-		handle->start();
-	}
-}
-
-void Thread::kill()
-{
-	if (handle)
-	{
-		Lock lock((Mutex *) _gcmutex);
-		handle->kill();
-		delete handle;
-		handle = 0;
-	}
-}
-
-void Thread::wait()
-{
-	if (handle)
-	{
-		handle->wait();
-		delete handle;
-		handle = 0;
-	}
-}
-
-void Thread::lock()
-{
-	mutex->lock();
-}
-
-void Thread::unlock()
-{
-	mutex->unlock();
-}
-
-std::string Thread::getName()
-{
-	return name;
-}
-
-Variant *Thread::get(const std::string &name)
-{
-	Variant *v = comm->getValue(name);
-	if (v)
-		v->retain();
-	return v;
-}
-
-std::vector<std::string> Thread::getKeys()
-{
-	return comm->getKeys();
-}
-
-Variant *Thread::demand(const std::string &name)
-{
-	Variant *v = comm->getValue(name);
-	while (!v)
-	{
-		if (comm->getValue("error"))
-			return 0;
-		cond->wait(mutex);
-		v = comm->getValue(name);
-	}
-	v->retain();
-	return v;
-}
-
-void Thread::clear(const std::string &name)
-{
-	comm->clearValue(name);
-}
-
-void Thread::set(const std::string &name, Variant *v)
-{
-	lock(); //this function explicitly locks
-	comm->setValue(name, v); //because we need
-	unlock(); //it to unlock here for the cond
-	cond->broadcast();
-}
-
-ThreadModule::ThreadModule()
-{
-	threads["main"] = new Thread(this, "main");
-}
-
-ThreadModule::~ThreadModule()
-{
-	for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)
-	{
-		i->second->kill();
-		delete i->second;
-	}
-}
-
-Thread *ThreadModule::newThread(const std::string &name, love::Data *data)
-{
-	if (threads.count(name) != 0)
-		return 0;
-	Thread *t = new Thread(this, name, data);
-	threads[name] = t;
-	return t;
-}
-
-Thread *ThreadModule::getThread(const std::string &name)
-{
-	if (threads.count(name) == 0)
-		return 0;
-	threadlist_t::iterator i = threads.find(name);
-	return i->second;
-}
-
-void ThreadModule::getThreads(Thread **list)
-{
-	int c = 0;
-	for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++, c++)
-	{
-		list[c] = i->second;
-	}
-}
-
-unsigned ThreadModule::getThreadCount() const
-{
-	return threads.size();
-}
-
-void ThreadModule::unregister(const std::string &name)
-{
-	if (threads.count(name) == 0)
-		return;
-	threadlist_t::iterator i = threads.find(name);
-	// FIXME: shouldn't the thread be deleted?
-	threads.erase(i);
-}
-
-const char *ThreadModule::getName() const
-{
-	return "love.thread.sdl";
-}
-
-} // thread
-} // love

File src/modules/thread/Thread.h

View file
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_THREAD_SDL_THREAD_H
-#define LOVE_THREAD_SDL_THREAD_H
-
-// STL
-#include <map>
-#include <string>
-#include <vector>
-#include <cstring>
+#ifndef LOVE_THREAD_THREAD_H
+#define LOVE_THREAD_THREAD_H
 
 // LOVE
-#include "filesystem/File.h"
-#include "common/runtime.h"
-#include "common/Module.h"
-#include "common/Variant.h"
-#include "thread/threads.h"
+#include <common/runtime.h>
+#include <common/Object.h>
 
 namespace love
 {
 namespace thread
 {
 
-class ThreadModule;
-
-class ThreadData
+class Thread
 {
 public:
-	ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond);
-	~ThreadData();
-	const char *getCode();
-	const char *getName(size_t *len = 0);
-	Variant *getValue(const std::string &name);
-	void clearValue(const std::string &name);
-	void setValue(const std::string &name, Variant *v);
-	std::vector<std::string> getKeys();
+	virtual ~Thread() {}
+	virtual bool start() = 0;
+	virtual void wait() = 0;
+	virtual void kill() = 0;
+}; // ThreadObject
 
-	void *mutex;
-	void *cond;
-private:
-	char *code;
-	char *name;
-	std::map<std::string, Variant *> shared;
-	size_t len;
-};
-
-class Thread : public love::Object
-{
-public:
-	Thread(love::thread::ThreadModule *module, const std::string &name, love::Data *data);
-	Thread(love::thread::ThreadModule *module, const std::string &name);
-	virtual ~Thread();
-	void start();
-	void kill();
-	void wait();
-	std::string getName();
-	Variant *get(const std::string &name);
-	std::vector<std::string> getKeys();
-	Variant *demand(const std::string &name);
-	void clear(const std::string &name);
-	void set(const std::string &name, Variant *v);
-	void lock();
-	void unlock();
-private:
-	class ThreadThread: public ThreadBase
-	{
-	private:
-		ThreadData *comm;
-
-	protected:
-		virtual void main();
-
-	public:
-		ThreadThread(ThreadData *comm);
-	};
-
-	ThreadThread *handle;
-
-	ThreadModule *module;
-	ThreadData *comm;
-	std::string name;
-	char *data;
-	Mutex *mutex;
-	Conditional *cond;
-	bool isThread;
-}; // Thread
-
-typedef std::map<std::string, Thread *> threadlist_t;
-
-class ThreadModule : public love::Module
-{
-public:
-	ThreadModule();
-	virtual ~ThreadModule();
-	Thread *newThread(const std::string &name, love::Data *data);
-	void getThreads(Thread **list);
-	Thread *getThread(const std::string &name);
-	unsigned getThreadCount() const;
-	void unregister(const std::string &name);
-	const char *getName() const;
-private:
-	threadlist_t threads;
-}; // ThreadModule
 } // thread
 } // love
 
-#endif // LOVE_THREAD_SDL_THREAD_H
+#endif // LOVE_THREAD_THREAD_H

File src/modules/thread/ThreadModule.cpp

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "ThreadModule.h"
+
+namespace love
+{
+namespace thread
+{
+const char *ThreadModule::getName() const
+{
+	return "love.thread.sdl";
+}
+
+LuaThread *ThreadModule::newThread(const std::string &name, love::Data *data)
+{
+	LuaThread *lt = new LuaThread(name, data);
+	return lt;
+}
+
+Channel *ThreadModule::newChannel()
+{
+	return new Channel();
+}
+
+Channel *ThreadModule::getChannel(const std::string &name)
+{
+	return Channel::getChannel(name);
+}
+} // thread
+} // love

File src/modules/thread/ThreadModule.h

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#ifndef LOVE_THREAD_THREADMODULE_H
+#define LOVE_THREAD_THREADMODULE_H
+
+// STL
+#include <string>
+
+// LOVE
+#include <common/Data.h>
+#include <common/Module.h>
+#include <thread/Thread.h>
+#include <thread/Channel.h>
+#include <thread/LuaThread.h>
+#include <thread/threads.h>
+
+namespace love
+{
+namespace thread
+{
+class ThreadModule : public love::Module
+{
+public:
+	virtual ~ThreadModule() {}
+	LuaThread *newThread(const std::string &name, love::Data *data);
+	Channel *newChannel();
+	Channel *getChannel(const std::string &name);
+
+	const char *getName() const;
+}; // ThreadModule
+} // thread
+} // love
+
+#endif // LOVE_THREAD_THREADMODULE_H

File src/modules/thread/posix/threads.cpp

-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#include "threads.h"
-#ifdef LOVE_MACOSX
-#include "common/delay.h" // for Mac OS X's fake sem_timedwait
-#endif
-
-namespace love
-{
-namespace thread
-{
-
-Mutex::Mutex()
-{
-	pthread_mutex_init(&mutex, NULL);
-}
-
-Mutex::~Mutex()
-{
-	pthread_mutex_destroy(&mutex);
-}
-
-void Mutex::lock()
-{
-	pthread_mutex_lock(&mutex);
-}
-
-void Mutex::unlock()
-{
-	pthread_mutex_unlock(&mutex);
-}
-
-void *ThreadBase::thread_runner(void *param)
-{
-	ThreadBase *thread = (ThreadBase *)param;
-	thread->main();
-	return NULL;
-}
-
-ThreadBase::ThreadBase()
-	: running(false)
-{
-	pthread_t thread;
-}
-
-ThreadBase::~ThreadBase()
-{
-	if (running)
-	{
-		wait();
-	}
-}
-
-bool ThreadBase::start()
-{
-	if (pthread_create(&thread, NULL, thread_runner, this))
-		return false;
-	return (running = true);
-}
-
-void ThreadBase::wait()
-{
-	pthread_join(thread, NULL);
-	running = false;
-}
-
-void ThreadBase::kill()
-{
-	pthread_kill(thread, 9);
-	running = false;
-}
-
-unsigned int ThreadBase::threadId()
-{
-	return (unsigned int)((size_t)pthread_self());
-}
-
-Semaphore::Semaphore(unsigned int initial_value)
-{
-	sem_init(&sem, 0, initial_value);
-}
-
-Semaphore::~Semaphore()
-{
-	sem_destroy(&sem);
-}
-
-unsigned int Semaphore::value()
-{
-	int val = 0;
-	if (sem_getvalue(&sem, &val))
-		return 0;
-	else
-		return val;
-}
-
-void Semaphore::post()
-{
-	sem_post(&sem);
-}
-
-bool Semaphore::wait(int timeout)
-{
-	if (timeout < 0)
-		return !sem_wait(&sem);
-	else if (timeout == 0)
-		return !sem_trywait(&sem);
-	else
-	{
-#ifdef LOVE_MACOSX
-		// OS X lacks sem_timedwait, so we fake it with a busy loop
-		time_t timer = time(NULL)*1000 + timeout;
-		int retval = 0;
-		do
-		{
-			retval = sem_trywait(&sem);
-			if (retval == 0) break;
-			delay(1);
-		}
-		while (time(NULL)*1000 < timer);
-		return !retval;
-#else
-		struct timespec ts;
-		ts.tv_sec = timeout/1000;
-		ts.tv_nsec = (timeout % 1000) * 1000000;
-		return !sem_timedwait(&sem, &ts);
-#endif
-	}
-}
-
-bool Semaphore::tryWait()
-{
-	return !sem_trywait(&sem);
-}
-
-Conditional::Conditional()
-{
-	pthread_cond_init(&cond, NULL);
-}
-
-Conditional::~Conditional()
-{
-	pthread_cond_destroy(&cond);
-}
-
-void Conditional::signal()
-{
-	pthread_cond_signal(&cond);
-}
-
-void Conditional::broadcast()
-{
-	pthread_cond_broadcast(&cond);
-}
-
-bool Conditional::wait(Mutex *mutex, int timeout)
-{
-	if (timeout < 0)
-		return !pthread_cond_wait(&cond, &mutex->mutex);
-	else
-	{
-		struct timespec ts;
-		int ret;
-
-		ts.tv_sec = timeout / 1000;
-		ts.tv_nsec = (timeout % 1000) * 1000000;
-
-		ret = pthread_cond_timedwait(&cond, &mutex->mutex, &ts);
-		return (ret == 0);
-	}
-}
-} // thread
-} // love
-

File src/modules/thread/posix/threads.h

-/**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
-
-#ifndef LOVE_THREAD_POSIX_THREADS_H
-#define LOVE_THREAD_POSIX_THREADS_H
-
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-
-namespace love
-{
-namespace thread
-{
-class Mutex
-{
-public:
-	Mutex();
-	~Mutex();
-
-	void lock();
-	void unlock();
-
-private:
-	pthread_mutex_t mutex;
-	Mutex(const Mutex &mutex) {}
-
-	friend class Conditional;
-};
-
-
-class ThreadBase
-{
-public:
-	ThreadBase();
-	virtual ~ThreadBase();
-
-	bool start();
-	void wait();
-	void kill();
-
-	static unsigned int threadId();
-
-protected:
-	virtual void main() = 0;
-
-private:
-	pthread_t thread;
-	ThreadBase(ThreadBase &thread) {}
-
-	static void *thread_runner(void *param);
-	bool running;
-};
-
-class Semaphore
-{
-public:
-	Semaphore(unsigned int initial_value);
-	~Semaphore();
-
-	unsigned int value();
-	void post();
-	bool wait(int timeout = -1);
-	bool tryWait();
-
-private:
-	Semaphore(const Semaphore &sem) {}
-	sem_t sem;
-};
-
-// Should conditional inherit from mutex?
-class Conditional
-{
-public:
-	Conditional();
-	~Conditional();
-
-	void signal();
-	void broadcast();
-	bool wait(Mutex *mutex, int timeout=-1);
-
-private:
-	pthread_cond_t cond;
-};
-
-} // thread
-} // love
-
-
-#endif // LOVE_THREAD_POSIX_THREADS_H

File src/modules/thread/sdl/Thread.cpp

View file
+/**
+* Copyright (c) 2006-2012 LOVE Development Team
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+*
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+*
+* 1. The origin of this software must not be misrepresented; you must not
+*    claim that you wrote the original software. If you use this software
+*    in a product, an acknowledgment in the product documentation would be
+*    appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+*    misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+**/
+
+#include "Thread.h"
+
+namespace love
+{
+namespace thread
+{
+namespace sdl
+{
+Thread::Thread(Threadable *t)
+	: t(t)
+	, running(false)
+	, thread(0)
+{
+}
+
+Thread::~Thread()
+{
+	if (!running) // Clean up handle
+		wait();
+	/*
+	if (running)
+		wait();
+	FIXME: Needed for proper thread cleanup
+	*/
+}
+
+bool Thread::start()
+{
+	Lock l(mutex);
+	if (running)
+		return false;
+	if (thread) // Clean old handle up
+		SDL_WaitThread(thread, 0);