Browse Source

Working communication in love.thread

[email protected] 15 years ago
parent
commit
2dcd11551c

+ 130 - 7
src/modules/thread/sdl/Thread.cpp

@@ -25,7 +25,7 @@
 #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
 {
@@ -41,14 +41,74 @@ namespace sdl
 		love::luax_preload(L, luaopen_love, "love");
 		luaopen_love(L);
 	#endif // LOVE_BUILD_STANDALONE
-		luaL_dostring(L, comm->getCode());
+		luaopen_love_thread(L);
+		lua_pushstring(L, comm->getName());
+		luax_convobj(L, lua_gettop(L), "thread", "getThread");
+		lua_setglobal(L, "thread");
+		if(luaL_dostring(L, comm->getCode()) == 1)
+		{
+			ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1));
+			comm->setValue("error", v);
+			v->release();
+		}
 		lua_close(L);
 		return 0;
 	}
 
-	ThreadData::ThreadData(const char *code)
-		: code(code)
+	ThreadVariant::ThreadVariant(bool boolean)
+	{
+		type = BOOLEAN;
+		data.boolean = boolean;
+	}
+
+	ThreadVariant::ThreadVariant(double number)
+	{
+		type = NUMBER;
+		data.number = number;
+	}
+
+	ThreadVariant::ThreadVariant(const char *string)
 	{
+		type = STRING;
+		size_t len = strlen(string);
+		char *buf = new char[len+1];
+		memset(buf, 0, len+1);
+		memcpy(buf, string, len);
+		data.string = buf;
+	}
+
+	ThreadVariant::ThreadVariant(void *userdata)
+	{
+		type = USERDATA;
+		data.userdata = userdata;
+	}
+
+	ThreadVariant::~ThreadVariant()
+	{
+		switch(type)
+		{
+			case STRING:
+				delete[] data.string;
+				break;
+		}
+	}
+
+	ThreadData::ThreadData(const char *name, const char *code)
+	{
+		size_t len = strlen(name);
+		this->name = new char[len+1];
+		memset(this->name, 0, len+1);
+		memcpy(this->name, name, len);
+		len = strlen(code);
+		this->code = new char[len+1];
+		memset(this->code, 0, len+1);
+		memcpy(this->code, code, len);
+	}
+
+	ThreadData::~ThreadData()
+	{
+		delete[] name;
+		delete[] code;
 	}
 
 	const char *ThreadData::getCode()
@@ -56,33 +116,81 @@ namespace sdl
 		return code;
 	}
 
+	const char *ThreadData::getName()
+	{
+		return name;
+	}
+
+	ThreadVariant* ThreadData::getValue(std::string name)
+	{
+		if (shared.count(name) == 0)
+			return 0;
+		return shared[name];
+	}
+
+	void ThreadData::setValue(std::string name, ThreadVariant *v)
+	{
+		if (shared.count(name) != 0)
+			shared[name]->release();
+		v->retain();
+		shared[name] = v;
+	}
+
 	Thread::Thread(ThreadModuleRegistrar *reg, std::string name, love::Data *data)
 		: reg(reg), name(name), handle(0)
 	{
+		reg->retain();
 		unsigned int len = data->getSize();
-		this->data = new char[len];
+		this->data = new char[len+1];
+		memset(this->data, 0, len+1);
 		memcpy(this->data, data->getData(), len);
-		comm = new ThreadData(this->data);
+		comm = new ThreadData(name.c_str(), this->data);
+		mutex = SDL_CreateMutex();
 	}
 
 	Thread::~Thread()
 	{
 		delete[] data;
+		delete comm;
 		if (handle)
 			SDL_KillThread(handle);
 		reg->unregister(name);
+		SDL_DestroyMutex(mutex);
+		reg->release();
 	}
 
 	void Thread::start()
 	{
 		if (!handle)
-			SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm);
+			handle = SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm);
 	}
 
 	void Thread::kill()
 	{
 		if (handle)
+		{
 			SDL_KillThread(handle);
+			handle = 0;
+		}
+	}
+
+	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()
@@ -90,6 +198,21 @@ namespace sdl
 		return name;
 	}
 
+	ThreadVariant *Thread::receive(std::string name)
+	{
+		lock();
+		ThreadVariant *v = comm->getValue(name);
+		unlock();
+		return v;
+	}
+
+	void Thread::send(std::string name, ThreadVariant *v)
+	{
+		lock();
+		comm->setValue(name, v);
+		unlock();
+	}
+
 	ThreadModule::~ThreadModule()
 	{
 		for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)

+ 35 - 15
src/modules/thread/sdl/Thread.h

@@ -23,6 +23,7 @@
 
 // SDL
 #include <SDL_thread.h>
+#include <SDL_mutex.h>
 
 // STL
 #include <map>
@@ -39,40 +40,53 @@ namespace thread
 {
 namespace sdl
 {
-	class ThreadModuleRegistrar
+	class ThreadModuleRegistrar : public Module
 	{
 	public:
 		virtual void unregister(std::string name) = 0;
 	};
 
-	struct ThreadVariant
+	enum ThreadVariantType
 	{
-		enum type
-		{
-			UNKNOWN = 0,
-			BOOLEAN,
-			NUMBER,
-			STRING,
-			USERDATA
-		};
-		union data
+		UNKNOWN = 0,
+		BOOLEAN,
+		NUMBER,
+		STRING,
+		USERDATA
+	};
+
+	class ThreadVariant : public love::Object
+	{
+	public:
+		ThreadVariant(bool boolean);
+		ThreadVariant(double number);
+		ThreadVariant(const char *string);
+		ThreadVariant(void *userdata);
+		~ThreadVariant();
+		ThreadVariantType type;
+		union
 		{
 			bool boolean;
 			double number;
 			const char *string;
 			void *userdata;
-		};
+		} data;
 	};
 
 	class ThreadData
 	{
 	private:
-		const char *code;
+		char *code;
+		char *name;
 		std::map<std::string, ThreadVariant*> shared;
 
 	public:
-		ThreadData(const char *code);
+		ThreadData(const char *name, const char *code);
+		~ThreadData();
 		const char *getCode();
+		const char *getName();
+		ThreadVariant* getValue(std::string name);
+		void setValue(std::string name, ThreadVariant *v);
 	};
 
 	class Thread : public love::Object
@@ -83,18 +97,24 @@ namespace sdl
 		ThreadData *comm;
 		std::string name;
 		char *data;
+		SDL_mutex *mutex;
 
 	public:
 		Thread(ThreadModuleRegistrar *reg, std::string name, love::Data *data);
 		~Thread();
 		void start();
 		void kill();
+		void wait();
 		std::string getName();
+		ThreadVariant *receive(std::string name);
+		void send(std::string name, ThreadVariant *v);
+		void lock();
+		void unlock();
 	}; // Thread
 
 	typedef std::map<std::string, Thread*> threadlist_t;
 
-	class ThreadModule : public Module, ThreadModuleRegistrar
+	class ThreadModule : public ThreadModuleRegistrar
 	{
 	private:
 		threadlist_t threads;

+ 81 - 2
src/modules/thread/sdl/wrap_Thread.cpp

@@ -45,6 +45,13 @@ namespace sdl
 		return 0;
 	}
 
+	int w_Thread_wait(lua_State *L)
+	{
+		Thread *t = luax_checkthread(L, 1);
+		t->wait();
+		return 0;
+	}
+
 	int w_Thread_getName(lua_State *L)
 	{
 		Thread *t = luax_checkthread(L, 1);
@@ -52,10 +59,73 @@ namespace sdl
 		return 1;
 	}
 
+	int w_Thread_receive(lua_State *L)
+	{
+		Thread *t = luax_checkthread(L, 1);
+		ThreadVariant *v = t->receive(luaL_checkstring(L, 2));
+		if (v)
+		{
+			switch(v->type)
+			{
+				case BOOLEAN:
+					lua_pushboolean(L, v->data.boolean);
+					break;
+				case NUMBER:
+					lua_pushnumber(L, v->data.number);
+					break;
+				case STRING:
+					lua_pushstring(L, v->data.string);
+					break;
+				case USERDATA: //FIXME: full userdata
+					lua_pushlightuserdata(L, v->data.userdata);
+					break;
+				default:
+					lua_pushnil(L);
+					break;
+			}
+		}
+		else
+			lua_pushnil(L);
+		return 1;
+	}
+
+	int w_Thread_send(lua_State *L)
+	{
+		Thread *t = luax_checkthread(L, 1);
+		std::string name = luaL_checkstring(L, 2);
+		ThreadVariant *v;
+		if (lua_isboolean(L, 3))
+		{
+			v = new ThreadVariant((bool) lua_toboolean(L, 3));
+		}
+		else if (lua_isnumber(L, 3))
+		{
+			v = new ThreadVariant(lua_tonumber(L, 3));
+		}
+		else if (lua_isstring(L, 3))
+		{
+			v = new ThreadVariant(lua_tostring(L, 3));
+		}
+		else if (lua_islightuserdata(L, 3))
+		{
+			v = new ThreadVariant(lua_touserdata(L, 3));
+		}
+		else
+		{
+			return luaL_error(L, "Expected boolean, number, string or userdata");
+		}
+		t->send(name, v);
+		v->release();
+		return 0;
+	}
+
 	static const luaL_Reg type_functions[] = {
 		{ "start", w_Thread_start },
 		{ "kill", w_Thread_kill },
+		{ "wait", w_Thread_wait },
 		{ "getName", w_Thread_getName },
+		{ "receive", w_Thread_receive },
+		{ "send", w_Thread_send },
 		{ 0, 0 }
 	};
 
@@ -86,8 +156,15 @@ namespace sdl
 	{
 		std::string name = luaL_checkstring(L, 1);
 		Thread *t = instance->getThread(name);
-		luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
-		t->retain();
+		if (t)
+		{
+			luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t);
+			t->lock();
+			t->retain();
+			t->unlock();
+		}
+		else
+			lua_pushnil(L);
 		return 1;
 	}
 
@@ -117,6 +194,8 @@ namespace sdl
 				return luaL_error(L, e.what());
 			}
 		}
+		else
+			instance->retain();
 
 		WrappedModule w;
 		w.module = instance;

+ 4 - 1
src/modules/thread/sdl/wrap_Thread.h

@@ -34,7 +34,10 @@ namespace sdl
 	Thread *luax_checkthread(lua_State *L, int idx);
 	int w_Thread_start(lua_State *L);
 	int w_Thread_kill(lua_State *L);
-	int w_thread_getName(lua_State *L);
+	int w_Thread_wait(lua_State *L);
+	int w_Thread_getName(lua_State *L);
+	int w_Thread_receive(lua_State *L);
+	int w_Thread_send(lua_State *L);
 
 	int luaopen_thread(lua_State *L);