From 2dcd11551ce8a7494b33eeaec461ee205afbcb7b Mon Sep 17 00:00:00 2001 From: "bart@bartbes.ath.cx" Date: Sun, 14 Feb 2010 10:09:21 +0100 Subject: [PATCH] Working communication in love.thread --- src/modules/thread/sdl/Thread.cpp | 137 +++++++++++++++++++++++-- src/modules/thread/sdl/Thread.h | 50 ++++++--- src/modules/thread/sdl/wrap_Thread.cpp | 83 ++++++++++++++- src/modules/thread/sdl/wrap_Thread.h | 5 +- 4 files changed, 250 insertions(+), 25 deletions(-) diff --git a/src/modules/thread/sdl/Thread.cpp b/src/modules/thread/sdl/Thread.cpp index d68dc1e34..6253d226f 100644 --- a/src/modules/thread/sdl/Thread.cpp +++ b/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++) diff --git a/src/modules/thread/sdl/Thread.h b/src/modules/thread/sdl/Thread.h index 1f2abcbc3..470bbd0f1 100644 --- a/src/modules/thread/sdl/Thread.h +++ b/src/modules/thread/sdl/Thread.h @@ -23,6 +23,7 @@ // SDL #include +#include // STL #include @@ -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 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 threadlist_t; - class ThreadModule : public Module, ThreadModuleRegistrar + class ThreadModule : public ThreadModuleRegistrar { private: threadlist_t threads; diff --git a/src/modules/thread/sdl/wrap_Thread.cpp b/src/modules/thread/sdl/wrap_Thread.cpp index 091dd262a..be06d058d 100644 --- a/src/modules/thread/sdl/wrap_Thread.cpp +++ b/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; diff --git a/src/modules/thread/sdl/wrap_Thread.h b/src/modules/thread/sdl/wrap_Thread.h index 5a0a41f12..825e68fc3 100644 --- a/src/modules/thread/sdl/wrap_Thread.h +++ b/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);