From 399a6a661426f05186af210412d1a379deb86ee5 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Wed, 4 Jul 2012 17:15:16 +0200 Subject: [PATCH] Merge in channels from love-experiments Rewritten love.thread and changed communication method from weird system before, to channels. --HG-- branch : minor --- platform/unix/exclude | 3 - src/common/Object.h | 1 - src/common/delay.cpp | 12 +- src/common/delay.h | 2 - src/common/runtime.cpp | 14 +- src/common/runtime.h | 9 + src/common/types.h | 2 + src/modules/audio/openal/Audio.cpp | 12 +- src/modules/audio/openal/Audio.h | 8 +- src/modules/audio/openal/Pool.cpp | 2 +- src/modules/event/Event.cpp | 6 + src/modules/event/Event.h | 4 +- src/modules/image/ImageData.cpp | 12 + src/modules/image/ImageData.h | 6 +- src/modules/image/devil/ImageData.cpp | 8 +- src/modules/image/devil/ImageData.h | 5 + src/modules/thread/Channel.cpp | 148 ++++++++ src/modules/thread/Channel.h | 61 ++++ src/modules/thread/LuaThread.cpp | 68 ++++ src/modules/thread/LuaThread.h | 52 +++ src/modules/thread/Thread.cpp | 317 ------------------ src/modules/thread/Thread.h | 102 +----- src/modules/thread/ThreadModule.cpp | 49 +++ src/modules/thread/ThreadModule.h | 52 +++ src/modules/thread/posix/threads.cpp | 192 ----------- src/modules/thread/posix/threads.h | 107 ------ src/modules/thread/sdl/Thread.cpp | 90 +++++ src/modules/thread/sdl/Thread.h | 57 ++++ src/modules/thread/sdl/threads.cpp | 111 ++---- src/modules/thread/sdl/threads.h | 98 ++---- src/modules/thread/threads.cpp | 55 ++- src/modules/thread/threads.h | 88 +++-- src/modules/thread/win32/threads.cpp | 211 ------------ src/modules/thread/win32/threads.h | 107 ------ src/modules/thread/wrap_Channel.cpp | 107 ++++++ src/modules/thread/wrap_Channel.h | 43 +++ src/modules/thread/wrap_LuaThread.cpp | 71 ++++ .../{wrap_Thread.h => wrap_LuaThread.h} | 24 +- src/modules/thread/wrap_Thread.cpp | 290 ---------------- src/modules/thread/wrap_ThreadModule.cpp | 126 +++++++ src/modules/thread/wrap_ThreadModule.h | 40 +++ 41 files changed, 1192 insertions(+), 1580 deletions(-) create mode 100644 src/modules/thread/Channel.cpp create mode 100644 src/modules/thread/Channel.h create mode 100644 src/modules/thread/LuaThread.cpp create mode 100644 src/modules/thread/LuaThread.h delete mode 100644 src/modules/thread/Thread.cpp create mode 100644 src/modules/thread/ThreadModule.cpp create mode 100644 src/modules/thread/ThreadModule.h delete mode 100644 src/modules/thread/posix/threads.cpp delete mode 100644 src/modules/thread/posix/threads.h create mode 100644 src/modules/thread/sdl/Thread.cpp create mode 100644 src/modules/thread/sdl/Thread.h delete mode 100644 src/modules/thread/win32/threads.cpp delete mode 100644 src/modules/thread/win32/threads.h create mode 100644 src/modules/thread/wrap_Channel.cpp create mode 100644 src/modules/thread/wrap_Channel.h create mode 100644 src/modules/thread/wrap_LuaThread.cpp rename src/modules/thread/{wrap_Thread.h => wrap_LuaThread.h} (65%) delete mode 100644 src/modules/thread/wrap_Thread.cpp create mode 100644 src/modules/thread/wrap_ThreadModule.cpp create mode 100644 src/modules/thread/wrap_ThreadModule.h diff --git a/platform/unix/exclude b/platform/unix/exclude index a81932b20..931966fe6 100644 --- a/platform/unix/exclude +++ b/platform/unix/exclude @@ -21,7 +21,4 @@ \./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 diff --git a/src/common/Object.h b/src/common/Object.h index 00ba9230a..301fce214 100644 --- a/src/common/Object.h +++ b/src/common/Object.h @@ -70,7 +70,6 @@ private: // The reference count. int count; }; // Object - } // love #endif // LOVE_OBJECT_H diff --git a/src/common/delay.cpp b/src/common/delay.cpp index dbd072794..dde6e90d8 100644 --- a/src/common/delay.cpp +++ b/src/common/delay.cpp @@ -19,24 +19,14 @@ **/ #include "delay.h" +#include 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 diff --git a/src/common/delay.h b/src/common/delay.h index a35b7668d..670a75d7f 100644 --- a/src/common/delay.h +++ b/src/common/delay.h @@ -21,8 +21,6 @@ #ifndef DELAY_H_ #define DELAY_H_ -#include - namespace love { diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 5216890b6..d7f45a33d 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -25,7 +25,7 @@ #include "Object.h" #include "Reference.h" #include "StringMap.h" -#include "thread/threads.h" +#include // STD #include @@ -35,7 +35,6 @@ namespace love 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. @@ -44,7 +43,7 @@ static int w__gc(lua_State *L) { if (!gcmutex) { - gcmutex = new thread::Mutex(); + gcmutex = thread::newMutex(); _gcmutex = (void *) gcmutex; } Proxy *p = (Proxy *)lua_touserdata(L, 1); @@ -52,7 +51,6 @@ static int w__gc(lua_State *L) if (p->own) { thread::Lock lock(gcmutex); - _gcthread = thread::ThreadBase::threadId(); t->release(); } return 0; @@ -118,6 +116,13 @@ bool luax_optboolean(lua_State *L, int idx, bool b) 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; @@ -462,6 +467,7 @@ StringMap::Entry typeEntries[] = // Thread {"Thread", THREAD_THREAD_ID}, + {"Channel", THREAD_CHANNEL_ID}, // The modules themselves. Only add abstracted modules here. {"filesystem", MODULE_FILESYSTEM_ID}, diff --git a/src/common/runtime.h b/src/common/runtime.h index 3d3c2a5e1..014f497bf 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -132,6 +132,15 @@ void luax_pushboolean(lua_State *L, bool b); **/ bool luax_optboolean(lua_State *L, int idx, bool b); +/** + * 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_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. diff --git a/src/common/types.h b/src/common/types.h index f245edfa3..5b39631dd 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -89,6 +89,7 @@ enum Type // Thread THREAD_THREAD_ID, + THREAD_CHANNEL_ID, // The modules themselves. Only add abstracted modules here. MODULE_FILESYSTEM_ID, @@ -160,6 +161,7 @@ const bits PHYSICS_WHEEL_JOINT_T = (bits(1) << PHYSICS_WHEEL_JOINT_ID) | PHYSICS // 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; diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index e63cf69d8..df0914f17 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -23,6 +23,8 @@ #include "sound/Decoder.h" +#include + namespace love { namespace audio @@ -34,9 +36,16 @@ Audio::PoolThread::PoolThread(Pool *pool) : pool(pool) , finish(false) { + mutex = thread::newMutex(); } -void Audio::PoolThread::main() +Audio::PoolThread::~PoolThread() +{ + delete mutex; +} + + +void Audio::PoolThread::threadFunction() { while (true) { @@ -59,7 +68,6 @@ void Audio::PoolThread::setFinish() finish = true; } - Audio::Audio() : distanceModel(DISTANCE_INVERSE_CLAMPED) { // Passing zero for default device. diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index 03e2e602b..214871df0 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -109,7 +109,7 @@ private: // The Pool. Pool *pool; - class PoolThread: public thread::ThreadBase + class PoolThread: public thread::Threadable { protected: Pool *pool; @@ -120,13 +120,13 @@ private: 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; diff --git a/src/modules/audio/openal/Pool.cpp b/src/modules/audio/openal/Pool.cpp index 14e9699dd..329c7a796 100644 --- a/src/modules/audio/openal/Pool.cpp +++ b/src/modules/audio/openal/Pool.cpp @@ -35,7 +35,7 @@ Pool::Pool() 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."); diff --git a/src/modules/event/Event.cpp b/src/modules/event/Event.cpp index cb9b332a7..bbdf4785b 100644 --- a/src/modules/event/Event.cpp +++ b/src/modules/event/Event.cpp @@ -80,8 +80,14 @@ Message *Message::fromLua(lua_State *L, int n) return m; } +Event::Event() +{ + mutex = thread::newMutex(); +} + Event::~Event() { + delete mutex; } void Event::push(Message *msg) diff --git a/src/modules/event/Event.h b/src/modules/event/Event.h index 7aa11e92a..f07c475b8 100644 --- a/src/modules/event/Event.h +++ b/src/modules/event/Event.h @@ -54,6 +54,7 @@ public: class Event : public Module { public: + Event(); virtual ~Event(); void push(Message *msg); @@ -68,13 +69,12 @@ public: static bool getConstant(love::keyboard::Keyboard::Key in, const char *&out); protected: - thread::Mutex mutex; + thread::Mutex *mutex; std::queue queue; static StringMap::Entry buttonEntries[]; static StringMap buttons; static StringMap::Entry keyEntries[]; static StringMap keys; - }; // Event } // event diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index 13880ee01..6cb2f0818 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -20,6 +20,8 @@ #include "ImageData.h" +#include + using love::thread::Lock; namespace love @@ -27,6 +29,16 @@ namespace love namespace image { +ImageData::ImageData() +{ + mutex = thread::newMutex(); +} + +ImageData::~ImageData() +{ + delete mutex; +} + void *ImageData::getData() const { return data; diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index ebc9df682..31c244802 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -59,7 +59,7 @@ protected: // We need to be thread-safe // so we lock when we're accessing our // data - Mutex mutex; + Mutex *mutex; public: @@ -73,10 +73,12 @@ 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); diff --git a/src/modules/image/devil/ImageData.cpp b/src/modules/image/devil/ImageData.cpp index 3c6303f26..d14057cd7 100644 --- a/src/modules/image/devil/ImageData.cpp +++ b/src/modules/image/devil/ImageData.cpp @@ -31,7 +31,7 @@ using love::thread::Lock; -static Mutex devilMutex; +static Mutex *devilMutex = 0; namespace love { @@ -96,6 +96,9 @@ void ImageData::create(int width, int height, void *data) void ImageData::load(Data *data) { + if (!devilMutex) + devilMutex = thread::newMutex(); + Lock lock(devilMutex); ILuint image; ilGenImages(1, &image); @@ -132,6 +135,9 @@ void ImageData::load(Data *data) void ImageData::encode(love::filesystem::File *f, ImageData::Format format) { + if (!devilMutex) + devilMutex = thread::newMutex(); + Lock lock1(devilMutex); Lock lock2(mutex); diff --git a/src/modules/image/devil/ImageData.h b/src/modules/image/devil/ImageData.h index 1b9769214..5ad610a13 100644 --- a/src/modules/image/devil/ImageData.h +++ b/src/modules/image/devil/ImageData.h @@ -57,6 +57,11 @@ public: // 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 diff --git a/src/modules/thread/Channel.cpp b/src/modules/thread/Channel.cpp new file mode 100644 index 000000000..69930eca3 --- /dev/null +++ b/src/modules/thread/Channel.cpp @@ -0,0 +1,148 @@ +/** +* 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 +#include + +namespace love +{ +namespace thread +{ + static std::map 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) + { + mutex = newMutex(); + cond = newConditional(); + } + + Channel::Channel(const std::string &name) + : named(true), name(name) + { + mutex = newMutex(); + cond = newConditional(); + } + + Channel::~Channel() + { + while (!queue.empty()) + { + queue.front()->release(); + queue.pop(); + } + + delete mutex; + delete cond; + if (named) + { + Lock l(namedChannelMutex); + namedChannels.erase(name); + } + } + + void Channel::push(Variant *var) + { + if (!var) + return; + 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->signal(); + } + + Variant *Channel::pop() + { + Lock l(mutex); + if (queue.empty()) + return 0; + + Variant *var = queue.front(); + queue.pop(); + + // 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; + while (!(var = pop())) + { + mutex->lock(); + 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); + while (!queue.empty()) + { + queue.front()->release(); + queue.pop(); + } + + // Once again, release our own + // reference if we're named. + if (named) + release(); + } +} // thread +} // love diff --git a/src/modules/thread/Channel.h b/src/modules/thread/Channel.h new file mode 100644 index 000000000..09db2c86c --- /dev/null +++ b/src/modules/thread/Channel.h @@ -0,0 +1,61 @@ +/** +* 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 +#include + +// LOVE +#include +#include + +namespace love +{ +namespace thread +{ + class Channel : public love::Object + { + private: + Mutex *mutex; + Conditional *cond; + std::queue queue; + bool named; + std::string name; + Channel(const std::string &name); + + public: + Channel(); + ~Channel(); + static Channel *getChannel(const std::string &name); + + void push(Variant *var); + Variant *pop(); + Variant *demand(); + Variant *peek(); + int count(); + void clear(); + }; // Channel +} // thread +} // love + +#endif // LOVE_THREAD_CHANNEL_H diff --git a/src/modules/thread/LuaThread.cpp b/src/modules/thread/LuaThread.cpp new file mode 100644 index 000000000..2440a9fed --- /dev/null +++ b/src/modules/thread/LuaThread.cpp @@ -0,0 +1,68 @@ +/** +* 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 + +#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 diff --git a/src/modules/thread/LuaThread.h b/src/modules/thread/LuaThread.h new file mode 100644 index 000000000..9888b79f1 --- /dev/null +++ b/src/modules/thread/LuaThread.h @@ -0,0 +1,52 @@ +/** +* 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 + +// LOVE +#include +#include +#include + +namespace love +{ +namespace thread +{ + class LuaThread : public love::Object, public Threadable + { + private: + love::Data *code; + std::string name; + std::string error; + + public: + LuaThread(const std::string &name, love::Data *code); + ~LuaThread(); + void threadFunction(); + const std::string &getError(); + }; +} // thread +} // love + +#endif // LOVE_THREAD_LUATHREAD_H diff --git a/src/modules/thread/Thread.cpp b/src/modules/thread/Thread.cpp deleted file mode 100644 index d792a1e58..000000000 --- a/src/modules/thread/Thread.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/** - * 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 "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); - 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) - : 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; -} - -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 ThreadData::getKeys() -{ - std::vector keys; - for (std::map::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 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 diff --git a/src/modules/thread/Thread.h b/src/modules/thread/Thread.h index 170d1a01c..5ebe9de34 100644 --- a/src/modules/thread/Thread.h +++ b/src/modules/thread/Thread.h @@ -18,108 +18,28 @@ * 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 -#include -#include -#include +#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 +#include 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 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 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 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 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 diff --git a/src/modules/thread/ThreadModule.cpp b/src/modules/thread/ThreadModule.cpp new file mode 100644 index 000000000..7e2804e05 --- /dev/null +++ b/src/modules/thread/ThreadModule.cpp @@ -0,0 +1,49 @@ +/** +* 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 diff --git a/src/modules/thread/ThreadModule.h b/src/modules/thread/ThreadModule.h new file mode 100644 index 000000000..909e06e10 --- /dev/null +++ b/src/modules/thread/ThreadModule.h @@ -0,0 +1,52 @@ +/** +* 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 + +// LOVE +#include +#include +#include +#include +#include +#include + +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 diff --git a/src/modules/thread/posix/threads.cpp b/src/modules/thread/posix/threads.cpp deleted file mode 100644 index e4247b235..000000000 --- a/src/modules/thread/posix/threads.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/** - * 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 "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 - diff --git a/src/modules/thread/posix/threads.h b/src/modules/thread/posix/threads.h deleted file mode 100644 index 959eb08c0..000000000 --- a/src/modules/thread/posix/threads.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * 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_POSIX_THREADS_H -#define LOVE_THREAD_POSIX_THREADS_H - -#include -#include -#include - -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 diff --git a/src/modules/thread/sdl/Thread.cpp b/src/modules/thread/sdl/Thread.cpp new file mode 100644 index 000000000..63fb248d4 --- /dev/null +++ b/src/modules/thread/sdl/Thread.cpp @@ -0,0 +1,90 @@ +/** +* 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); + thread = SDL_CreateThread(thread_runner, this); + running = (thread != 0); + return running; + } + + void Thread::wait() + { + mutex.lock(); + if (!thread) + return; + mutex.unlock(); + SDL_WaitThread(thread, 0); + Lock l(mutex); + running = false; + thread = 0; + } + + void Thread::kill() + { + Lock l(mutex); + if (!running) + return; + SDL_KillThread(thread); + SDL_WaitThread(thread, 0); + running = false; + thread = 0; + } + + int Thread::thread_runner(void *data) + { + Thread *self = (Thread*) data; // some compilers don't like 'this' + self->t->threadFunction(); + Lock l(self->mutex); + self->running = false; + return 0; + } +} // sdl +} // thread +} // love diff --git a/src/modules/thread/sdl/Thread.h b/src/modules/thread/sdl/Thread.h new file mode 100644 index 000000000..27ced1fac --- /dev/null +++ b/src/modules/thread/sdl/Thread.h @@ -0,0 +1,57 @@ +/** +* 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_SDL_THREAD_H +#define LOVE_THREAD_SDL_THREAD_H + +// LOVE +#include +#include "threads.h" + +// SDL +#include + +namespace love +{ +namespace thread +{ +namespace sdl +{ + class Thread : public thread::Thread + { + private: + Threadable *t; + bool running; + SDL_Thread *thread; + static int thread_runner(void *data); + Mutex mutex; + + public: + Thread(Threadable *t); + ~Thread(); + bool start(); + void kill(); + void wait(); + }; // Thread +} // sdl +} // thread +} // love + +#endif // LOVE_THREAD_SDL_THREAD_H diff --git a/src/modules/thread/sdl/threads.cpp b/src/modules/thread/sdl/threads.cpp index 9497d5046..e90595c09 100644 --- a/src/modules/thread/sdl/threads.cpp +++ b/src/modules/thread/sdl/threads.cpp @@ -19,12 +19,14 @@ **/ #include "threads.h" +#include "Thread.h" namespace love { namespace thread { - +namespace sdl +{ Mutex::Mutex() { mutex = SDL_CreateMutex(); @@ -45,90 +47,6 @@ void Mutex::unlock() SDL_mutexV(mutex); } -int ThreadBase::thread_runner(void *param) -{ - ThreadBase *thread = (ThreadBase *)param; - thread->main(); - return 0; -} - -ThreadBase::ThreadBase() - : running(false) -{ -} - -ThreadBase::~ThreadBase() -{ - if (running) - { - wait(); - } -} - -bool ThreadBase::start() -{ - thread = SDL_CreateThread(thread_runner, this); - if (thread == NULL) - return false; - else - return (running = 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); - return (ret == 0); - } -} - -bool Semaphore::tryWait() -{ - return SDL_SemTryWait(semaphore) ? false : true; -} - Conditional::Conditional() { cond = SDL_CreateCond(); @@ -149,13 +67,34 @@ void Conditional::broadcast() SDL_CondBroadcast(cond); } -bool Conditional::wait(Mutex *mutex, int timeout) +bool Conditional::wait(thread::Mutex *_mutex, int timeout) { + // Yes, I realise this can be dangerous, + // however, you're asking for it if you're + // mixing thread implementations. + Mutex *mutex = (Mutex*) _mutex; if (timeout < 0) return !SDL_CondWait(cond, mutex->mutex); else return (SDL_CondWaitTimeout(cond, mutex->mutex, timeout) == 0); } +} // sdl + +thread::Mutex *newMutex() +{ + return new sdl::Mutex(); +} + +thread::Conditional *newConditional() +{ + return new sdl::Conditional(); +} + +thread::Thread *newThread(Threadable *t) +{ + return new sdl::Thread(t); +} + } // thread } // love diff --git a/src/modules/thread/sdl/threads.h b/src/modules/thread/sdl/threads.h index 678b49d04..7c3c848c0 100644 --- a/src/modules/thread/sdl/threads.h +++ b/src/modules/thread/sdl/threads.h @@ -21,87 +21,51 @@ #ifndef LOVE_THREAD_SDL_THREADS_H #define LOVE_THREAD_SDL_THREADS_H -#include "SDL.h" -#include "common/config.h" +#include +#include + +#include namespace love { namespace thread { - -class Mutex +namespace sdl { -public: - Mutex(); - ~Mutex(); + class Conditional; - void lock(); - void unlock(); -private: - SDL_mutex *mutex; - Mutex(const Mutex &/* mutex*/) {} + class Mutex : public thread::Mutex + { + public: + Mutex(); + ~Mutex(); - friend class Conditional; -}; + void lock(); + void unlock(); + private: + SDL_mutex* mutex; + Mutex(const Mutex&/* mutex*/) {} + friend class Conditional; + }; -class ThreadBase -{ -public: - ThreadBase(); - virtual ~ThreadBase(); + class Conditional : public thread::Conditional + { + public: + Conditional(); + ~Conditional(); - bool start(); - void wait(); - void kill(); // FIXME: not supported by SDL (SDL's kill is probably cancel)? + void signal(); + void broadcast(); + bool wait(thread::Mutex* mutex, int timeout=-1); - static unsigned int threadId(); - -protected: - virtual void main() = 0; - -private: - SDL_Thread *thread; - ThreadBase(ThreadBase &/* thread*/) {} - bool running; - - static int thread_runner(void *param); -}; - -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*/) {} - SDL_sem *semaphore; -}; - -// Should conditional inherit from mutex? -class Conditional -{ -public: - Conditional(); - ~Conditional(); - - void signal(); - void broadcast(); - bool wait(Mutex *mutex, int timeout=-1); - -private: - SDL_cond *cond; -}; + private: + SDL_cond* cond; + }; +} // sdl } // thread } // love - -#endif // LOVE_THREAD_SDL_THREADS_H +#endif /* LOVE_THREAD_SDL_THREADS_H */ diff --git a/src/modules/thread/threads.cpp b/src/modules/thread/threads.cpp index 900fbd779..f2297a0ee 100644 --- a/src/modules/thread/threads.cpp +++ b/src/modules/thread/threads.cpp @@ -20,28 +20,51 @@ #include "threads.h" -#if LOVE_THREADS == LOVE_THREADS_POSIX -# include "posix/threads.cpp" -#elif LOVE_THREADS == LOVE_THREADS_WIN32 -# include "win32/threads.cpp" -#elif LOVE_THREADS == LOVE_THREADS_SDL -# include "sdl/threads.cpp" -#endif - namespace love { namespace thread { -const char *threadAPI() +Lock::Lock(Mutex *m) + : mutex(m) { -#if LOVE_THREADS == LOVE_THREADS_POSIX - return "posix"; -#elif LOVE_THREADS == LOVE_THREADS_WIN32 - return "win32"; -#elif LOVE_THREADS == LOVE_THREADS_SDL - return "sdl"; -#endif + mutex->lock(); +} + +Lock::Lock(Mutex &m) + : mutex(&m) +{ + mutex->lock(); +} + +Lock::~Lock() +{ + mutex->unlock(); +} + +Threadable::Threadable() +{ + owner = newThread(this); +} + +Threadable::~Threadable() +{ + delete owner; +} + +bool Threadable::start() +{ + return owner->start(); +} + +void Threadable::wait() +{ + owner->wait(); +} + +void Threadable::kill() +{ + owner->kill(); } } // thread diff --git a/src/modules/thread/threads.h b/src/modules/thread/threads.h index f3e903b23..f7ffe71f3 100644 --- a/src/modules/thread/threads.h +++ b/src/modules/thread/threads.h @@ -21,66 +21,64 @@ #ifndef LOVE_THREAD_THREADS_H #define LOVE_THREAD_THREADS_H -#include "common/config.h" - -#define LOVE_THREADS_SDL 0 -#define LOVE_THREADS_WIN32 1 -#define LOVE_THREADS_POSIX 2 - -// Choose correct threads API. -// Headless love uses either windows threads or posix threads. -// Headed (standard) love uses SDL threads. -#ifdef LOVE_HEADLESS -# ifdef WIN32 -# define LOVE_THREADS LOVE_THREADS_WIN32 -# else -# define LOVE_THREADS LOVE_THREADS_POSIX -# endif -#else -# define LOVE_THREADS LOVE_THREADS_SDL -#endif - - -// include the correct header -#if LOVE_THREADS == LOVE_THREADS_POSIX -# include "posix/threads.h" -#elif LOVE_THREADS == LOVE_THREADS_WIN32 -# include "win32/threads.h" -#elif LOVE_THREADS == LOVE_THREADS_SDL -# include "sdl/threads.h" -#endif - +#include +#include "Thread.h" namespace love { namespace thread { -const char *threadAPI(); +class Mutex +{ +public: + virtual ~Mutex() {} + + virtual void lock() = 0; + virtual void unlock() = 0; +}; + +class Conditional +{ +public: + virtual ~Conditional() {} + + virtual void signal() = 0; + virtual void broadcast() = 0; + virtual bool wait(Mutex* mutex, int timeout=-1) = 0; +}; class Lock { public: - Lock(Mutex *m): mutex(m) - { - mutex->lock(); - } + Lock(Mutex* m); + Lock(Mutex& m); + ~Lock(); - Lock(Mutex &m): mutex(&m) - { - mutex->lock(); - } - - ~Lock() - { - mutex->unlock(); - } private: Mutex *mutex; - - Lock(Lock &/* lock*/) {} }; +class Threadable +{ +public: + Threadable(); + virtual ~Threadable(); + + virtual void threadFunction() = 0; + + bool start(); + void wait(); + void kill(); + +protected: + Thread *owner; +}; + +Mutex *newMutex(); +Conditional *newConditional(); +Thread *newThread(Threadable *t); + } // thread } // love diff --git a/src/modules/thread/win32/threads.cpp b/src/modules/thread/win32/threads.cpp deleted file mode 100644 index 572d8dad5..000000000 --- a/src/modules/thread/win32/threads.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/** - * 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 "threads.h" - -namespace love -{ -namespace thread -{ - -Mutex::Mutex() -{ - InitializeCriticalSection(&mutex); -} - -Mutex::~Mutex() -{ - DeleteCriticalSection(&mutex); -} - -void Mutex::lock() -{ - EnterCriticalSection(&mutex); -} - -void Mutex::unlock() -{ - LeaveCriticalSection(&mutex); -} - -int ThreadBase::thread_runner(void *param) -{ - ThreadBase *thread = (ThreadBase *)param; - thread->main(); - return 0; -} - -ThreadBase::ThreadBase() - : running(false) -{ -} - -ThreadBase::~ThreadBase() -{ - if (running) - wait(); -} - -bool ThreadBase::start() -{ - thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) thread_runner, this, 0, NULL); - if (thread == NULL) - return false; - else - return (running = true); -} - -void ThreadBase::wait() -{ - WaitForSingleObject(thread, INFINITE); - CloseHandle(thread); - running = false; -} - -void ThreadBase::kill() -{ - TerminateThread(thread, FALSE); - running = false; -} - -unsigned int ThreadBase::threadId() -{ - return (unsigned int)GetCurrentThreadId(); -} - -Semaphore::Semaphore(unsigned int initial_value) - : count(initial_value) -{ - semaphore = CreateSemaphore(NULL, initial_value, UINT_MAX, NULL); -} - -Semaphore::~Semaphore() -{ - CloseHandle(semaphore); -} - -unsigned int Semaphore::value() -{ - return count; -} - -void Semaphore::post() -{ - InterlockedIncrement(&count); - if (ReleaseSemaphore(semaphore, 1, NULL) == FALSE) - InterlockedDecrement(&count); -} - -bool Semaphore::wait(int timeout) -{ - int result; - - result = WaitForSingleObject(semaphore, timeout < 0 ? INFINITE : timeout); - if (result == WAIT_OBJECT_0) - { - InterlockedDecrement(&count); - return true; - } - else - return false; -} - -bool Semaphore::tryWait() -{ - return wait(0); -} - - -// Conditional variable implementation based on semaphores. -// Vista+ builds should probably use CONDITIONAL_VARIABLE. -// -// based on http://www.cs.wustl.edu/~schmidt/win32-cv-2.html and ACE - - -Conditional::Conditional() - : waiting(0), signals(0) -{ -} - -Conditional::~Conditional() -{ -} - -void Conditional::signal() -{ - mutex.lock(); - if (waiting > signals) - { - signals++; - sem.post(); - mutex.unlock(); - done.wait(); - } - else - { - mutex.unlock(); - } -} - -void Conditional::broadcast() -{ - mutex.lock(); - if (waiting > signals) - { - int num = waiting - signals; - signals = waiting; - for (int i = 0; i < num; i++) - sem.post(); - mutex.unlock(); - for (int i = 0; i < num; i++) - done.wait(); - } - else - { - mutex.unlock(); - } -} - -bool Conditional::wait(Mutex *cmutex, int timeout) -{ - mutex.lock(); - waiting++; - mutex.unlock(); - - cmutex->unlock(); - bool ret = sem.wait(timeout); - - mutex.lock(); - if (signals > 0) - { - if (!ret) - sem.wait(); - done.post(); - signals--; - } - waiting--; - mutex.unlock(); - cmutex->lock(); - - return true; -} - -} // thread -} // love diff --git a/src/modules/thread/win32/threads.h b/src/modules/thread/win32/threads.h deleted file mode 100644 index 3822f46be..000000000 --- a/src/modules/thread/win32/threads.h +++ /dev/null @@ -1,107 +0,0 @@ -/** - * 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_WIN32_THREADS_H -#define LOVE_THREAD_WIN32_THREADS_H - -#include -#include - -namespace love -{ -namespace thread -{ - -class Mutex -{ -public: - Mutex(); - ~Mutex(); - - void lock(); - void unlock(); -private: - CRITICAL_SECTION mutex; - Mutex(const Mutex &mutex) {} -}; - -class ThreadBase -{ -public: - ThreadBase(); - virtual ~ThreadBase(); - - bool start(); - void wait(); - void kill(); - - static unsigned int threadId(); - -protected: - - virtual void main() = 0; - -private: - HANDLE thread; - ThreadBase(ThreadBase &thread) {} - bool running; - - static int WINAPI thread_runner(void *param); -}; - - -class Semaphore -{ -public: - Semaphore(unsigned int initial_value = 0); - ~Semaphore(); - - unsigned int value(); - void post(); - bool wait(int timeout = -1); - bool tryWait(); -private: - Semaphore(const Semaphore &sem) {} - HANDLE semaphore; - unsigned int count; -}; - - -// Should conditional inherit from mutex? -class Conditional -{ -public: - Conditional(); - ~Conditional(); - - void signal(); - void broadcast(); - bool wait(Mutex *cmutex, int timeout=-1); -private: - Mutex mutex; - int waiting; - int signals; - Semaphore sem; - Semaphore done; -}; -} // thread -} // love - -#endif /* LOVE_THREAD_WIN32_THREADS_H */ diff --git a/src/modules/thread/wrap_Channel.cpp b/src/modules/thread/wrap_Channel.cpp new file mode 100644 index 000000000..4ad6d0fcf --- /dev/null +++ b/src/modules/thread/wrap_Channel.cpp @@ -0,0 +1,107 @@ +/** +* Copyright (c) 2006-2010 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 "wrap_Channel.h" + +namespace love +{ +namespace thread +{ + Channel *luax_checkchannel(lua_State *L, int idx) + { + return luax_checktype(L, idx, "Channel", THREAD_CHANNEL_T); + } + + int w_Channel_push(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + Variant *var = Variant::fromLua(L, 2); + c->push(var); + var->release(); + return 0; + } + + int w_Channel_pop(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + Variant *var = c->pop(); + if (var) + { + var->toLua(L); + var->release(); + } + else + lua_pushnil(L); + return 1; + } + + int w_Channel_demand(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + Variant *var = c->demand(); + var->toLua(L); + var->release(); + return 1; + } + + int w_Channel_peek(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + Variant *var = c->peek(); + if (var) + { + var->toLua(L); + var->release(); + } + else + lua_pushnil(L); + return 1; + } + + int w_Channel_count(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + lua_pushnumber(L, c->count()); + return 1; + } + + int w_Channel_clear(lua_State *L) + { + Channel *c = luax_checkchannel(L, 1); + c->clear(); + return 0; + } + + static const luaL_Reg type_functions[] = { + { "push", w_Channel_push }, + { "pop", w_Channel_pop }, + { "demand", w_Channel_demand }, + { "peek", w_Channel_peek }, + { "count", w_Channel_count }, + { "clear", w_Channel_clear }, + { 0, 0 } + }; + + extern "C" int luaopen_channel(lua_State *L) + { + return luax_register_type(L, "Channel", type_functions); + } +} +} diff --git a/src/modules/thread/wrap_Channel.h b/src/modules/thread/wrap_Channel.h new file mode 100644 index 000000000..2f9f9332a --- /dev/null +++ b/src/modules/thread/wrap_Channel.h @@ -0,0 +1,43 @@ +/** +* 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_WRAP_CHANNEL_H +#define LOVE_THREAD_WRAP_CHANNEL_H + +// LOVE +#include "Channel.h" + +namespace love +{ +namespace thread +{ + Channel *luax_checkchannel(lua_State *L, int idx); + int w_Channel_push(lua_State *L); + int w_Channel_pop(lua_State *L); + int w_Channel_demand(lua_State *L); + int w_Channel_peek(lua_State *L); + int w_Channel_count(lua_State *L); + int w_Channel_clear(lua_State *L); + + extern "C" int luaopen_channel(lua_State *L); +} // thread +} // love + +#endif // LOVE_THREAD_WRAP_CHANNEL_H diff --git a/src/modules/thread/wrap_LuaThread.cpp b/src/modules/thread/wrap_LuaThread.cpp new file mode 100644 index 000000000..068810302 --- /dev/null +++ b/src/modules/thread/wrap_LuaThread.cpp @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2006-2010 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 "wrap_LuaThread.h" + +namespace love +{ +namespace thread +{ + +LuaThread *luax_checkthread(lua_State *L, int idx) +{ + return luax_checktype(L, idx, "Thread", THREAD_THREAD_T); +} + +int w_Thread_start(lua_State *L) +{ + LuaThread *t = luax_checkthread(L, 1); + luax_pushboolean(L, t->start()); + return 1; +} + +int w_Thread_wait(lua_State *L) +{ + LuaThread *t = luax_checkthread(L, 1); + t->wait(); + return 0; +} + +int w_Thread_getError(lua_State *L) +{ + LuaThread *t = luax_checkthread(L, 1); + std::string err = t->getError(); + if (err.length() == 0) + lua_pushnil(L); + else + luax_pushstring(L, err); + return 1; +} + +static const luaL_Reg type_functions[] = { + { "start", w_Thread_start }, + { "wait", w_Thread_wait }, + { "getError", w_Thread_getError }, + { 0, 0 } +}; + +extern "C" int luaopen_thread(lua_State *L) +{ + return luax_register_type(L, "Thread", type_functions); +} + +} // thread +} // love diff --git a/src/modules/thread/wrap_Thread.h b/src/modules/thread/wrap_LuaThread.h similarity index 65% rename from src/modules/thread/wrap_Thread.h rename to src/modules/thread/wrap_LuaThread.h index 6b77ad12a..8bfdf0731 100644 --- a/src/modules/thread/wrap_Thread.h +++ b/src/modules/thread/wrap_LuaThread.h @@ -18,37 +18,25 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_THREAD_SDL_WRAP_THREAD_H -#define LOVE_THREAD_SDL_WRAP_THREAD_H +#ifndef LOVE_THREAD_WRAP_LUATHREAD_H +#define LOVE_THREAD_WRAP_LUATHREAD_H // LOVE -#include "common/config.h" -#include "Thread.h" +#include "ThreadModule.h" namespace love { namespace thread { -Thread *luax_checkthread(lua_State *L, int idx); +LuaThread *luax_checkthread(lua_State *L, int idx); int w_Thread_start(lua_State *L); int w_Thread_wait(lua_State *L); -int w_Thread_getName(lua_State *L); -int w_Thread_get(lua_State *L); -int w_Thread_getKeys(lua_State *L); -int w_Thread_demand(lua_State *L); -int w_Thread_peek(lua_State *L); -int w_Thread_set(lua_State *L); +int w_Thread_getError(lua_State *L); extern "C" int luaopen_thread(lua_State *L); -int w_newThread(lua_State *L); -int w_getThreads(lua_State *L); -int w_getThread(lua_State *L); - -extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State *L); - } // thread } // love -#endif // LOVE_THREAD_SDL_WRAP_THREAD_H +#endif // LOVE_THREAD_WRAP_LUATHREAD_H diff --git a/src/modules/thread/wrap_Thread.cpp b/src/modules/thread/wrap_Thread.cpp deleted file mode 100644 index 1947e12da..000000000 --- a/src/modules/thread/wrap_Thread.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Copyright (c) 2006-2010 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 "wrap_Thread.h" - -namespace love -{ -namespace thread -{ - -Thread *luax_checkthread(lua_State *L, int idx) -{ - return luax_checktype(L, idx, "Thread", THREAD_THREAD_T); -} - -int w_Thread_start(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - t->start(); - 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); - // allow names containing \0 - luax_pushstring(L, t->getName()); - return 1; -} - - -int w_Thread_get(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - std::string name = luax_checkstring(L, 2); - t->lock(); - Variant *v = t->get(name); - t->clear(name); - t->unlock(); - if (!v) - { - lua_pushnil(L); - return 1; - } - v->toLua(L); - t->lock(); - v->release(); - t->unlock(); - return 1; -} - -int w_Thread_getKeys(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - t->lock(); - std::vector keys = t->getKeys(); - t->unlock(); - lua_createtable(L, keys.size(), 0); - int i = 1; - for (std::vector::iterator it = keys.begin(); it != keys.end(); it++) - { - lua_pushnumber(L, i++); - luax_pushstring(L, *it); - lua_settable(L, -3); - } - return 1; -} - -int w_Thread_demand(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - std::string name = luax_checkstring(L, 2); - t->lock(); - Variant *v = t->demand(name); - t->clear(name); - t->unlock(); - if (!v) - { - lua_pushnil(L); - return 1; - } - v->toLua(L); - t->lock(); - v->release(); - t->unlock(); - return 1; -} - -int w_Thread_peek(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - std::string name = luax_checkstring(L, 2); - t->lock(); - Variant *v = t->get(name); - t->unlock(); - if (!v) - { - lua_pushnil(L); - return 1; - } - v->toLua(L); - t->lock(); - v->release(); - t->unlock(); - return 1; -} - - -int w_Thread_set(lua_State *L) -{ - Thread *t = luax_checkthread(L, 1); - std::string name = luax_checkstring(L, 2); - Variant *v = Variant::fromLua(L, 3); - if (!v) - return luaL_error(L, "Expected boolean, number, string or userdata"); - t->set(name, v); - t->lock(); - v->release(); - t->unlock(); - return 0; -} - -static const luaL_Reg type_functions[] = -{ - { "start", w_Thread_start }, - { "wait", w_Thread_wait }, - { "getName", w_Thread_getName }, - { "get", w_Thread_get }, - { "getKeys", w_Thread_getKeys }, - { "demand", w_Thread_demand }, - { "peek", w_Thread_peek }, - { "set", w_Thread_set }, - { 0, 0 } -}; - -extern "C" int luaopen_thread(lua_State *L) -{ - return luax_register_type(L, "Thread", type_functions); -} - -static ThreadModule *instance; - -int w_newThread(lua_State *L) -{ - std::string name = luax_checkstring(L, 1); - love::Data *data; - if (lua_isstring(L, 2)) - luax_convobj(L, 2, "filesystem", "newFile"); - if (luax_istype(L, 2, FILESYSTEM_FILE_T)) - { - try - { - data = luax_checktype(L, 2, "File", FILESYSTEM_FILE_T)->read(); - } - catch(love::Exception &e) - { - return luaL_error(L, e.what()); - } - } - else - { - data = luax_checktype(L, 2, "Data", DATA_T); - data->retain(); - } - Thread *t = instance->newThread(name, data); - // do not worry, file->read() returns retained data - data->release(); - if (!t) - return luaL_error(L, "A thread with that name already exists."); - luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)t); - return 1; -} - -int w_getThreads(lua_State *L) -{ - unsigned count = instance->getThreadCount(); - Thread **list = new Thread*[count]; - instance->getThreads(list); - lua_newtable(L); - for (unsigned int i = 0; igetName()); - luax_newtype(L, "Thread", THREAD_THREAD_T, (void *) list[i]); - list[i]->lock(); - list[i]->retain(); - list[i]->unlock(); - lua_settable(L, -3); - } - delete[] list; - return 1; -} - -int w_getThread(lua_State *L) -{ - if (lua_isnoneornil(L, 1)) - { - lua_getglobal(L, "love"); - lua_getfield(L, -1, "_curthread"); - return 1; - } - std::string name = luax_checkstring(L, 1); - Thread *t = instance->getThread(name); - if (t) - { - luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)t); - t->lock(); - t->retain(); - t->unlock(); - } - else - lua_pushnil(L); - return 1; -} - - -// List of functions to wrap. -static const luaL_Reg module_functions[] = -{ - { "newThread", w_newThread }, - { "getThread", w_getThread }, - { "getThreads", w_getThreads }, - { 0, 0 } -}; - -static const lua_CFunction types[] = -{ - luaopen_thread, - 0 -}; - -extern "C" int luaopen_love_thread(lua_State *L) -{ - if (instance == 0) - { - try - { - instance = new ThreadModule(); - lua_getglobal(L, "love"); - Thread *curthread = instance->getThread("main"); - curthread->lock(); - curthread->retain(); - curthread->unlock(); - luax_newtype(L, "Thread", THREAD_THREAD_T, (void *)curthread); - lua_setfield(L, -2, "_curthread"); - } - catch(Exception &e) - { - return luaL_error(L, e.what()); - } - } - else - instance->retain(); - - WrappedModule w; - w.module = instance; - w.name = "thread"; - w.flags = MODULE_T; - w.functions = module_functions; - w.types = types; - - return luax_register_module(L, w); -} - -} // thread -} // love diff --git a/src/modules/thread/wrap_ThreadModule.cpp b/src/modules/thread/wrap_ThreadModule.cpp new file mode 100644 index 000000000..1a8505b73 --- /dev/null +++ b/src/modules/thread/wrap_ThreadModule.cpp @@ -0,0 +1,126 @@ +/** +* Copyright (c) 2006-2010 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 "wrap_ThreadModule.h" +#include "wrap_LuaThread.h" +#include "wrap_Channel.h" +#include +#include + +namespace love +{ +namespace thread +{ + static ThreadModule *instance = 0; + + int w_newThread(lua_State *L) + { + std::string name = "Thread code"; + love::Data *data; + if (lua_isstring(L, 1)) + luax_convobj(L, 1, "filesystem", "newFile"); + if (luax_istype(L, 1, FILESYSTEM_FILE_T)) + { + try + { + love::filesystem::File * file = luax_checktype(L, 1, "File", FILESYSTEM_FILE_T); + name = std::string("@") + file->getFilename(); + data = file->read(); + } + catch (love::Exception & e) + { + return luaL_error(L, "%s", e.what()); + } + } + else if (luax_istype(L, 1, FILESYSTEM_FILE_DATA_T)) + { + love::filesystem::FileData * fdata = luax_checktype(L, 1, "FileData", FILESYSTEM_FILE_DATA_T); + name = std::string("@") + fdata->getFilename(); + data = fdata; + data->retain(); + } + else + { + data = luax_checktype(L, 1, "Data", DATA_T); + data->retain(); + } + LuaThread *t = instance->newThread(name, data); + // do not worry, file->read() returns retained data + data->release(); + luax_newtype(L, "Thread", THREAD_THREAD_T, (void*)t); + return 1; + } + + int w_newChannel(lua_State *L) + { + Channel *c = instance->newChannel(); + luax_newtype(L, "Channel", THREAD_CHANNEL_T, (void*)c); + return 1; + } + + int w_getChannel(lua_State *L) + { + std::string name = luax_checkstring(L, 1); + Channel *c = instance->getChannel(name); + luax_newtype(L, "Channel", THREAD_CHANNEL_T, (void*)c); + return 1; + } + + // List of functions to wrap. + static const luaL_Reg module_functions[] = { + { "newThread", w_newThread }, + { "newChannel", w_newChannel }, + { "getChannel", w_getChannel }, + { 0, 0 } + }; + + static const lua_CFunction types[] = { + luaopen_thread, + luaopen_channel, + 0 + }; + + extern "C" int luaopen_love_thread(lua_State *L) + { + if (instance == 0) + { + try + { + instance = new ThreadModule(); + } + catch (Exception & e) + { + return luaL_error(L, "%s", e.what()); + } + } + else + instance->retain(); + + WrappedModule w; + w.module = instance; + w.name = "thread"; + w.flags = MODULE_T; + w.functions = module_functions; + w.types = types; + + return luax_register_module(L, w); + } +} +} diff --git a/src/modules/thread/wrap_ThreadModule.h b/src/modules/thread/wrap_ThreadModule.h new file mode 100644 index 000000000..9d88721e9 --- /dev/null +++ b/src/modules/thread/wrap_ThreadModule.h @@ -0,0 +1,40 @@ +/** +* 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_WRAP_THREADMODULE_H +#define LOVE_THREAD_WRAP_THREADMODULE_H + +// LOVE +#include "ThreadModule.h" + +namespace love +{ +namespace thread +{ + int w_newThread(lua_State *L); + int w_newChannel(lua_State *L); + int w_getChannel(lua_State *L); + + extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State * L); + +} // thread +} // love + +#endif // LOVE_THREAD_WRAP_THREADMODULE_H