1. Sebastian Dorda
  2. love-kinect-mindstorm

Commits

atheros  committed 9db17fb

Multiple thread backends.

  • Participants
  • Parent commits 9f4a5a2
  • Branches default

Comments (0)

Files changed (27)

File platform/unix/exclude

View file
  • Ignore whitespace
 ./modules/native/tcc/libtcc/stab.h
 ./libraries/luasocket/libluasocket/wsocket.*
 ./modules/sound/lullaby/FLACDecoder.*
+./modules/thread/sdl/*
+./modules/thread/win32/*
+./modules/thread/posix/*

File src/common/delay.cpp

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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 "delay.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
+	}
+
+} // namespace love

File src/common/delay.h

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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 DELAY_H_
+#define DELAY_H_
+
+#include <thread/threads.h>
+
+
+namespace love {
+
+	void delay(unsigned int ms);
+
+}; // namespace love
+
+#endif /* DELAY_H_ */

File src/common/runtime.cpp

View file
  • Ignore whitespace
 #include "Object.h"
 #include "Reference.h"
 #include "StringMap.h"
+#include <thread/threads.h>
 
 // STD
 #include <iostream>
 
-// SDL
-#include <SDL_mutex.h>
-#include <SDL_thread.h>
 
 namespace love
 {
-	static SDL_mutex *gcmutex = 0;
+	static thread::Mutex *gcmutex = 0;
 	void *_gcmutex = 0;
 	unsigned int _gcthread = 0;
 	/**
 	{
 		if (!gcmutex)
 		{
-			gcmutex = SDL_CreateMutex();
+			gcmutex = new thread::Mutex();
 			_gcmutex = (void*) gcmutex;
 		}
 		Proxy * p = (Proxy *)lua_touserdata(L, 1);
 		Object * t = (Object *)p->data;
 		if(p->own)
 		{
-			SDL_mutexP(gcmutex);
-			_gcthread = (unsigned int) SDL_ThreadID();
+			thread::Lock lock(gcmutex);
+			_gcthread = thread::ThreadBase::threadId();
 			t->release();
-			SDL_mutexV(gcmutex);
 		}
 		return 0;
 	}

File src/love.cpp

View file
  • Ignore whitespace
 #include <physics/box2d/wrap_Physics.h>
 #include <sound/wrap_Sound.h>
 #include <timer/sdl/wrap_Timer.h>
-#include <thread/sdl/wrap_Thread.h>
+#include <thread/wrap_Thread.h>
 
 // Libraries.
 #include "libraries/luasocket/luasocket.h"
 	{ "love.physics", love::physics::box2d::luaopen_love_physics },
 	{ "love.sound", love::sound::luaopen_love_sound },
 	{ "love.timer", love::timer::sdl::luaopen_love_timer },
-	{ "love.thread", love::thread::sdl::luaopen_love_thread },
+	{ "love.thread", love::thread::luaopen_love_thread },
 	{ 0, 0 }
 };
 

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

View file
  • Ignore whitespace
 **/
 
 #include "Audio.h"
+#include <common/delay.h>
 
 #include <sound/Decoder.h>
 
 {
 namespace openal
 {
+	Audio::PoolThread::PoolThread(Pool* pool)
+	: pool(pool), finish(false) {
+
+	}
+
+	void Audio::PoolThread::main()
+	{
+		while(true) {
+			{
+				thread::Lock lock(mutex);
+				if (finish) {
+					return;
+				}
+			}
+
+			pool->update();
+			delay(5);
+		}
+	}
+
+	void Audio::PoolThread::setFinish()
+	{
+		thread::Lock lock(mutex);
+		finish = true;
+	}
+
+
 	Audio::Audio()
-		: finish(false)
 	{
 		// Passing zero for default device.
 		device = alcOpenDevice(0);
 		// pool must be allocated after AL context.
 		pool = new Pool();
 
-		thread = SDL_CreateThread(Audio::run, (void*)this);
+		poolThread = new PoolThread(pool);
+		poolThread->start();
 	}
 
 	Audio::~Audio()
 	{
-		finish = true;
+		poolThread->setFinish();
+		poolThread->wait();
 
-		SDL_WaitThread(thread, 0);
-
+		delete poolThread;
 		delete pool;
 		
 		alcMakeContextCurrent(0);
 		alcCloseDevice(device);
 	}
 
-	int Audio::run(void * d)
-	{
-		Audio * instance = (Audio*)d;
-		
-		while(!instance->finish)
-		{
-			instance->pool->update();
-			SDL_Delay(5);
-		}
-
-		return 0;
-	}
 
 	const char * Audio::getName() const
 	{

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

View file
  • Ignore whitespace
 
 #include "Source.h"
 #include "Pool.h"
+#include <thread/threads.h>
 
 // OpenAL
 #ifdef LOVE_MACOSX
 		// The OpenAL context.
 		ALCcontext * context;
 
-		SDL_Thread * thread;
-
 		// The Pool.
 		Pool * pool;
 
-		// Set this to true when the thread should finish.
-		// Main thread will write to this value, and Audio::run
-		// will read from it.
-		bool finish;
 
-		static int run(void * unused);
+		class PoolThread: public thread::ThreadBase {
+		protected:
+			Pool* pool;
+
+			// Set this to true when the thread should finish.
+			// Main thread will write to this value, and PoolThread
+			// will read from it.
+			volatile bool finish;
+
+			// finish lock
+			thread::Mutex mutex;
+
+			virtual void main();
+
+		public:
+			PoolThread(Pool* pool);
+			void setFinish();
+		};
+
+		PoolThread* poolThread;
 
 	public:
 

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

View file
  • Ignore whitespace
 		alGenSources(NUM_SOURCES, sources);
 
 		// Create the mutex.
-		mutex = SDL_CreateMutex();
+		mutex = new thread::Mutex();
 
 		if(alGetError() != AL_NO_ERROR)
 			throw love::Exception("Could not generate sources.");
 	{
 		stop();
 
-		SDL_DestroyMutex(mutex);
+		delete mutex;
 
 		// Free all sources.
 		alDeleteSources(NUM_SOURCES, sources);
 	bool Pool::isAvailable() const
 	{
 		bool has = false;
-		LOCK(mutex);
-		has = !available.empty();
-		UNLOCK(mutex);
+		{
+			thread::Lock lock(mutex);
+			has = !available.empty();
+		}
 		return has;
 	}
 
 	bool Pool::isPlaying(Source * s)
 	{
 		bool p = false;
-		LOCK(mutex);
-		for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
 		{
-			if(i->first == s)
-				p = true;
+			thread::Lock lock(mutex);
+			for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
+			{
+				if(i->first == s)
+					p = true;
+			}
 		}
-		UNLOCK(mutex);
 		return p;
 	}
 
 	void Pool::update()
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 
 		std::map<Source *, ALuint>::iterator i = playing.begin();
 
 				i++;
 			}
 		}
-
-		UNLOCK(mutex);
 	}
 
 	int Pool::getNumSources() const
 		bool ok;
 		out = 0;
 
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 
 		bool alreadyPlaying = findSource(source, out);
 
 			ok = true;
 		}
 
-		UNLOCK(mutex);
-
 		return ok;
 	}
 
 	void Pool::stop()
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
 		{
 			i->first->stopAtomic();
 		}
 
 		playing.clear();
-
-		UNLOCK(mutex);
 	}
 
 	void Pool::stop(Source * source)
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		removeSource(source);
-		UNLOCK(mutex);
 	}
 
 	void Pool::pause()
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
 			i->first->pauseAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::pause(Source * source)
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		ALuint out;
 		if(findSource(source, out))
 			source->pauseAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::resume()
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
 			i->first->resumeAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::resume(Source * source)
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		ALuint out;
 		if(findSource(source, out))
 			source->resumeAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::rewind()
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
 			i->first->rewindAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::rewind(Source * source)
 	{
-		LOCK(mutex);
+		thread::Lock lock(mutex);
 		ALuint out;
 		if(findSource(source, out))
 			source->rewindAtomic();
-		UNLOCK(mutex);
 	}
 
 	void Pool::release(Source * source)

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

View file
  • Ignore whitespace
 // LOVE
 #include <common/config.h>
 #include <common/Exception.h>
+#include <thread/threads.h>
 
 // OpenAL
 #ifdef LOVE_MACOSX
 
 		// Only one thread can access this object at the same time. This mutex will
 		// make sure of that.
-		SDL_mutex * mutex;
+		thread::Mutex* mutex;
 
 	public:
 

File src/modules/thread/Thread.cpp

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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 = 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);
+		{
+			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);
+				ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
+				comm->setValue("error", v);
+				v->release();
+			}
+			((Conditional*) comm->cond)->broadcast();
+		}
+		lua_close(L);
+	}
+
+
+	ThreadVariant::ThreadVariant(bool boolean)
+	{
+		type = BOOLEAN;
+		data.boolean = boolean;
+	}
+
+	ThreadVariant::ThreadVariant(double number)
+	{
+		type = NUMBER;
+		data.number = number;
+	}
+
+	ThreadVariant::ThreadVariant(const char *string, size_t len)
+	{
+		type = STRING;
+		char *buf = new char[len+1];
+		memset(buf, 0, len+1);
+		memcpy(buf, string, len);
+		data.string.str = buf;
+		data.string.len = len;
+	}
+
+	ThreadVariant::ThreadVariant(void *userdata)
+	{
+		type = LUSERDATA;
+		data.userdata = userdata;
+	}
+
+	ThreadVariant::ThreadVariant(Type udatatype, void *userdata)
+	{
+		type = FUSERDATA;
+		this->udatatype = udatatype;
+		Proxy *p = (Proxy *) userdata;
+		flags = p->flags;
+		data.userdata = p->data;
+		((love::Object *) data.userdata)->retain();
+	}
+
+	ThreadVariant::~ThreadVariant()
+	{
+		switch(type)
+		{
+			case STRING:
+				delete[] data.string.str;
+				break;
+			case FUSERDATA:
+				((love::Object *) data.userdata)->release();
+				break;
+			default:
+				break;
+		}
+	}
+
+	ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond)
+		: len(len), mutex(mutex), cond(cond)
+	{
+		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;
+	}
+
+	ThreadVariant* 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, ThreadVariant *v)
+	{
+		if (shared.count(name) != 0)
+			shared[name]->release();
+		v->retain();
+		shared[name] = v;
+	}
+
+	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;
+	}
+
+	ThreadVariant *Thread::get(const std::string & name)
+	{
+		ThreadVariant *v = comm->getValue(name);
+		if (v)
+			v->retain();
+		return v;
+	}
+
+	ThreadVariant *Thread::demand(const std::string & name)
+	{
+		ThreadVariant *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, ThreadVariant *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
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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_SDL_THREAD_H
+#define LOVE_THREAD_SDL_THREAD_H
+
+// STL
+#include <map>
+#include <string>
+
+// LOVE
+#include <filesystem/File.h>
+#include <common/runtime.h>
+#include <common/Module.h>
+#include <thread/threads.h>
+
+
+namespace love
+{
+namespace thread
+{
+
+	class ThreadModule;
+
+	enum ThreadVariantType
+	{
+		UNKNOWN = 0,
+		BOOLEAN,
+		NUMBER,
+		STRING,
+		LUSERDATA,
+		FUSERDATA
+	};
+
+	class ThreadVariant : public love::Object
+	{
+	public:
+		ThreadVariant(bool boolean);
+		ThreadVariant(double number);
+		ThreadVariant(const char *string, size_t len);
+		ThreadVariant(void *userdata);
+		ThreadVariant(Type udatatype, void *userdata);
+		virtual ~ThreadVariant();
+		ThreadVariantType type;
+		union
+		{
+			bool boolean;
+			double number;
+			struct {
+				const char *str;
+				size_t len;
+			} string;
+			void *userdata;
+		} data;
+		Type udatatype;
+		bits flags;
+	};
+
+	class ThreadData
+	{
+	private:
+		char *code;
+		char *name;
+		std::map<std::string, ThreadVariant*> shared;
+		size_t len;
+
+	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);
+		ThreadVariant* getValue(const std::string & name);
+		void clearValue(const std::string & name);
+		void setValue(const std::string & name, ThreadVariant *v);
+
+		void *mutex;
+		void *cond;
+	};
+
+	class Thread : public love::Object
+	{
+	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;
+
+
+	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();
+		ThreadVariant *get(const std::string & name);
+		ThreadVariant *demand(const std::string & name);
+		void clear(const std::string & name);
+		void set(const std::string & name, ThreadVariant *v);
+		void lock();
+		void unlock();
+	}; // Thread
+
+	typedef std::map<std::string, Thread*> threadlist_t;
+
+	class ThreadModule : public love::Module
+	{
+	private:
+		threadlist_t threads;
+
+	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;
+	}; // ThreadModule
+} // thread
+} // love
+
+#endif // LOVE_THREAD_SDL_THREAD_H

File src/modules/thread/ThreadModule.h

  • Ignore whitespace
-/**
-* Copyright (c) 2006-2011 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_THREAD_H
-#define LOVE_THREAD_THREAD_H
-
-#include <common/Module.h>
-#include <string>
-
-namespace love
-{
-namespace thread
-{
-	class ThreadModule : public Module
-	{
-	public:
-		virtual ~ThreadModule(){};
-		virtual void unregister(const std::string & name) = 0;
-	}; // ThreadModule
-
-} // thread
-} // love
-
-#endif // LOVE_THREAD_THREAD_H

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

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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"
+
+namespace love
+{
+namespace thread
+{
+
+	Mutex::Mutex() {
+		pthread_create_mutex(&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;
+		} else {
+			running = true;
+			return true;
+		}
+	}
+
+
+	void ThreadBase::wait() {
+		pthread_join(thread, NULL);
+		running = false;
+	}
+
+
+	void ThreadBase::kill() {
+		// FIXME: I'm not sure about that one.
+		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) {
+			if (sem_wait(&sem)) {
+				return false;
+			} else {
+				return true;
+			}
+		} else if (timeout == 0) {
+			if (sem_trywait(&sem)) {
+				return false;
+			} else {
+				return true;
+			}
+		} else {
+			struct timespec ts;
+			ts.tv_sec = timeout/1000;
+			ts.tv_nsec = (timeout % 1000) * 1000000;
+			if (sem_timedwait(&sem, &ts)) {
+				return false; // either timeout or error...
+			} else {
+				return true;
+			}
+		}
+	}
+
+
+	bool Semaphore::tryWait() {
+		if (sem_trywait(&sem)) {
+			return false;
+		} else {
+			return true;
+		}
+	}
+
+
+
+
+	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) {
+			if (pthread_cond_wait(cond, mutex->mutex)) {
+				return false;
+			} else {
+				return true;
+			}
+		} 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);
+			if (ret == ETIMEDOUT) {
+				return false;
+			} else if (ret == 0) {
+				return true;
+			} else {
+				// something bad happend!
+				return false;
+			}
+		}
+	}
+} // namespace thread
+} // namespace love
+

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

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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_PLATFORM_POSIX_THREADS_H_
+#define LOVE_PLATFORM_POSIX_THREADS_H_
+
+#include <pthread.h>
+#include <semaphore.h>
+
+namespace love
+{
+namespace thread
+{
+
+	class Mutex {
+	private:
+		pthread_mutex_t mutex;
+		Mutex(const Mutex& mutex) {}
+
+		friend class Conditional;
+
+	public:
+		Mutex();
+		~Mutex();
+
+		 void lock();
+		 void unlock();
+	};
+
+
+	class ThreadBase {
+	private:
+		pthread_t thread;
+		ThreadBase(ThreadBase& thread) {}
+
+		static void* thread_runner(void* param);
+
+	protected:
+
+		virtual void main() = 0;
+
+	public:
+		ThreadBase();
+		virtual ~ThreadBase();
+
+		bool start();
+		void wait();
+		void kill();
+
+		static unsigned int threadId();
+	};
+
+	class Semaphore {
+	private:
+		Semaphore(const Semaphore& sem) {}
+		sem_t semaphore;
+
+	public:
+		Semaphore(unsigned int initial_value);
+		~Semaphore();
+
+		unsigned int value();
+		void post();
+		bool wait(int timeout = -1);
+		bool tryWait();
+	};
+
+	// Should conditional inherit from mutex?
+	class Conditional {
+	private:
+		pthread_cond_t cond;
+
+	public:
+		Conditional();
+		~Conditional();
+
+		void signal();
+		void broadcast();
+		bool wait(Mutex* mutex, int timeout=-1);
+	};
+
+} // namespace thread
+} // namespace love
+
+
+#endif // !LOVE_PLATFORM_POSIX_THREADS_H_

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

  • Ignore whitespace
-/**
-* Copyright (c) 2006-2011 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
-{
-namespace sdl
-{
-	int threadfunc(ThreadData *comm)
-	{
-		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);
-		{
-			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)
-		{
-			SDL_mutexP((SDL_mutex*) comm->mutex);
-			ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
-			comm->setValue("error", v);
-			v->release();
-			SDL_mutexV((SDL_mutex*) comm->mutex);
-			SDL_CondBroadcast((SDL_cond*) comm->cond);
-		}
-		lua_close(L);
-		return 0;
-	}
-
-	ThreadVariant::ThreadVariant(bool boolean)
-	{
-		type = BOOLEAN;
-		data.boolean = boolean;
-	}
-
-	ThreadVariant::ThreadVariant(double number)
-	{
-		type = NUMBER;
-		data.number = number;
-	}
-
-	ThreadVariant::ThreadVariant(const char *string, size_t len)
-	{
-		type = STRING;
-		char *buf = new char[len+1];
-		memset(buf, 0, len+1);
-		memcpy(buf, string, len);
-		data.string.str = buf;
-		data.string.len = len;
-	}
-
-	ThreadVariant::ThreadVariant(void *userdata)
-	{
-		type = LUSERDATA;
-		data.userdata = userdata;
-	}
-
-	ThreadVariant::ThreadVariant(Type udatatype, void *userdata)
-	{
-		type = FUSERDATA;
-		this->udatatype = udatatype;
-		Proxy *p = (Proxy *) userdata;
-		flags = p->flags;
-		data.userdata = p->data;
-		((love::Object *) data.userdata)->retain();
-	}
-
-	ThreadVariant::~ThreadVariant()
-	{
-		switch(type)
-		{
-			case STRING:
-				delete[] data.string.str;
-				break;
-			case FUSERDATA:
-				((love::Object *) data.userdata)->release();
-				break;
-			default:
-				break;
-		}
-	}
-
-	ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond)
-		: len(len), mutex(mutex), cond(cond)
-	{
-		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;
-	}
-
-	ThreadVariant* 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, ThreadVariant *v)
-	{
-		if (shared.count(name) != 0)
-			shared[name]->release();
-		v->retain();
-		shared[name] = v;
-	}
-
-	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 = SDL_CreateMutex();
-		cond = SDL_CreateCond();
-		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 = SDL_CreateMutex();
-		cond = SDL_CreateCond();
-		comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond);
-	}
-
-	Thread::~Thread()
-	{
-		if (data)
-			delete[] data;
-		delete comm;
-		module->unregister(name);
-		SDL_DestroyMutex(mutex);
-		SDL_DestroyCond(cond);
-		module->release();
-	}
-
-	void Thread::start()
-	{
-		if (!handle && isThread)
-			handle = SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm);
-	}
-
-	void Thread::kill()
-	{
-		if (handle)
-		{
-			SDL_mutexP((SDL_mutex *) _gcmutex);
-			SDL_KillThread(handle);
-			handle = 0;
-			SDL_mutexV((SDL_mutex *) _gcmutex);
-		}
-	}
-
-	void Thread::wait()
-	{
-		if (handle)
-		{
-			SDL_WaitThread(handle, NULL);
-			handle = 0;
-		}
-	}
-
-	void Thread::lock()
-	{
-		SDL_mutexP(mutex);
-	}
-
-	void Thread::unlock()
-	{
-		SDL_mutexV(mutex);
-	}
-
-	std::string Thread::getName()
-	{
-		return name;
-	}
-
-	ThreadVariant *Thread::get(const std::string & name)
-	{
-		ThreadVariant *v = comm->getValue(name);
-		if (v)
-			v->retain();
-		return v;
-	}
-
-	ThreadVariant *Thread::demand(const std::string & name)
-	{
-		ThreadVariant *v = comm->getValue(name);
-		while (!v)
-		{
-			if (comm->getValue("error"))
-				return 0;
-			SDL_CondWait(cond, 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, ThreadVariant *v)
-	{
-		lock(); //this function explicitly locks
-		comm->setValue(name, v); //because we need
-		unlock(); //it to unlock here for the cond
-		SDL_CondBroadcast(cond);
-	}
-
-	ThreadModule::ThreadModule()
-	{
-		threads["main"] = new Thread(this, "main");
-	}
-
-	ThreadModule::~ThreadModule()
-	{
-		for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)
-		{
-			i->second->kill();
-		}
-	}
-
-	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);
-		threads.erase(i);
-	}
-
-	const char *ThreadModule::getName() const
-	{
-		return "love.thread.sdl";
-	}
-} // sdl
-} // thread
-} // love

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

  • Ignore whitespace
-/**
-* Copyright (c) 2006-2011 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_SDL_THREAD_H
-#define LOVE_THREAD_SDL_THREAD_H
-
-// SDL
-#include <SDL_thread.h>
-#include <SDL_mutex.h>
-
-// STL
-#include <map>
-#include <string>
-
-// LOVE
-#include <thread/ThreadModule.h>
-#include <filesystem/File.h>
-#include <common/runtime.h>
-
-namespace love
-{
-namespace thread
-{
-namespace sdl
-{
-	enum ThreadVariantType
-	{
-		UNKNOWN = 0,
-		BOOLEAN,
-		NUMBER,
-		STRING,
-		LUSERDATA,
-		FUSERDATA
-	};
-
-	class ThreadVariant : public love::Object
-	{
-	public:
-		ThreadVariant(bool boolean);
-		ThreadVariant(double number);
-		ThreadVariant(const char *string, size_t len);
-		ThreadVariant(void *userdata);
-		ThreadVariant(Type udatatype, void *userdata);
-		virtual ~ThreadVariant();
-		ThreadVariantType type;
-		union
-		{
-			bool boolean;
-			double number;
-			struct {
-				const char *str;
-				size_t len;
-			} string;
-			void *userdata;
-		} data;
-		Type udatatype;
-		bits flags;
-	};
-
-	class ThreadData
-	{
-	private:
-		char *code;
-		char *name;
-		std::map<std::string, ThreadVariant*> shared;
-		size_t len;
-
-	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);
-		ThreadVariant* getValue(const std::string & name);
-		void clearValue(const std::string & name);
-		void setValue(const std::string & name, ThreadVariant *v);
-
-		void *mutex;
-		void *cond;
-	};
-
-	class Thread : public love::Object
-	{
-	private:
-		SDL_Thread *handle;
-		love::thread::ThreadModule *module;
-		ThreadData *comm;
-		std::string name;
-		char *data;
-		SDL_mutex *mutex;
-		SDL_cond *cond;
-		bool isThread;
-
-	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();
-		ThreadVariant *get(const std::string & name);
-		ThreadVariant *demand(const std::string & name);
-		void clear(const std::string & name);
-		void set(const std::string & name, ThreadVariant *v);
-		void lock();
-		void unlock();
-	}; // Thread
-
-	typedef std::map<std::string, Thread*> threadlist_t;
-
-	class ThreadModule : public love::thread::ThreadModule
-	{
-	private:
-		threadlist_t threads;
-
-	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;
-	}; // ThreadModule
-} // sdl
-} // thread
-} // love
-
-#endif // LOVE_THREAD_SDL_THREAD_H

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

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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"
+
+namespace love
+{
+namespace thread
+{
+
+	Mutex::Mutex() {
+		mutex = SDL_CreateMutex();
+	}
+
+	Mutex::~Mutex() {
+		SDL_DestroyMutex(mutex);
+	}
+
+	void Mutex::lock() {
+		SDL_mutexP(mutex);
+	}
+
+	void Mutex::unlock() {
+		SDL_mutexV(mutex);
+	}
+
+
+
+	int ThreadBase::thread_runner(void* param) {
+		ThreadBase* thread = (ThreadBase*)param;
+		thread->main();
+		return 0;
+	}
+
+	ThreadBase::ThreadBase() : running(false) {
+		SDL_Thread* thread;
+	}
+
+	ThreadBase::~ThreadBase() {
+		if (running) {
+			wait();
+		}
+	}
+
+	bool ThreadBase::start() {
+		thread = SDL_CreateThread(thread_runner, this);
+		if (thread == NULL) {
+			return false;
+		} else {
+			running = true;
+			return true;
+		}
+	}
+
+	void ThreadBase::wait() {
+		SDL_WaitThread(thread, NULL);
+		running = false;
+	}
+
+	void ThreadBase::kill() {
+		SDL_KillThread(thread);
+		running = false;
+	}
+
+	unsigned int ThreadBase::threadId() {
+		return (unsigned int)SDL_ThreadID();
+	}
+
+	Semaphore::Semaphore(unsigned int initial_value) {
+		semaphore = SDL_CreateSemaphore(initial_value);
+	}
+
+	Semaphore::~Semaphore() {
+		SDL_DestroySemaphore(semaphore);
+	}
+
+	unsigned int Semaphore::value() {
+		return SDL_SemValue(semaphore);
+	}
+
+	void Semaphore::post() {
+		SDL_SemPost(semaphore);
+	}
+
+	bool Semaphore::wait(int timeout) {
+		if (timeout < 0) {
+			return SDL_SemWait(semaphore) ? false : true;
+		} else if (timeout == 0) {
+			return SDL_SemTryWait(semaphore) ? false : true;
+		} else {
+			int ret = SDL_SemWaitTimeout(semaphore, timeout);
+			if (ret == SDL_MUTEX_TIMEDOUT) {
+				return false;
+			} else if (ret == 0) {
+				return true;
+			} else {
+				// some nasty error
+				return false;
+			}
+		}
+	}
+
+	bool Semaphore::tryWait() {
+		return SDL_SemTryWait(semaphore) ? false : true;
+	}
+
+
+
+	Conditional::Conditional() {
+		cond = SDL_CreateCond();
+	}
+
+	Conditional::~Conditional() {
+		SDL_DestroyCond(cond);
+	}
+
+	void Conditional::signal() {
+		SDL_CondSignal(cond);
+	}
+
+	void Conditional::broadcast()  {
+		SDL_CondBroadcast(cond);
+	}
+
+	bool Conditional::wait(Mutex* mutex, int timeout) {
+		if (timeout < 0) {
+			if (SDL_CondWait(cond, mutex->mutex)) {
+				// error
+				return false;
+			} else {
+				return true;
+			}
+		} else {
+			int ret = SDL_CondWaitTimeout(cond, mutex->mutex, timeout);
+			if (ret == SDL_MUTEX_TIMEDOUT) {
+				return false;
+			} else if (ret == 0) {
+				return true;
+			} else {
+				// some bad error
+				return false;
+			}
+		}
+	}
+
+} // namespace thread
+} // namespace love

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

View file
  • Ignore whitespace
+/**
+* Copyright (c) 2006-2011 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.
+**/
+