Multiple thread backends.

This commit is contained in:
Przemysław Grzywacz
2011-06-08 16:54:35 +02:00
parent 09ed781f66
commit 1d5fca6f46
22 changed files with 1208 additions and 132 deletions
+3
View File
@@ -21,3 +21,6 @@
./modules/native/tcc/libtcc/stab.h ./modules/native/tcc/libtcc/stab.h
./libraries/luasocket/libluasocket/wsocket.* ./libraries/luasocket/libluasocket/wsocket.*
./modules/sound/lullaby/FLACDecoder.* ./modules/sound/lullaby/FLACDecoder.*
./modules/thread/sdl/*
./modules/thread/win32/*
./modules/thread/posix/*
+41
View File
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "delay.h"
namespace love {
void delay(unsigned int ms) {
#if LOVE_THREADS == LOVE_THREADS_POSIX
struct timespec ts1, ts2;
ts1.tv_sec = ms / 1000;
ts1.tv_nsec = (ms % 1000) * 1000000;
// FIXME: handle signals
nanosleep(&ts1, &ts2);
#elif LOVE_THREADS == LOVE_THREADS_WIN32
Sleep(ms);
#elif LOVE_THREADS == LOVE_THREADS_SDL
SDL_Delay(ms);
#endif
}
} // namespace love
@@ -18,24 +18,16 @@
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
**/ **/
#ifndef LOVE_THREAD_THREAD_H #ifndef DELAY_H_
#define LOVE_THREAD_THREAD_H #define DELAY_H_
#include <common/Module.h> #include <thread/threads.h>
#include <string>
namespace love
{
namespace thread
{
class ThreadModule : public Module
{
public:
virtual ~ThreadModule(){};
virtual void unregister(const std::string & name) = 0;
}; // ThreadModule
} // thread namespace love {
} // love
#endif // LOVE_THREAD_THREAD_H void delay(unsigned int ms);
}; // namespace love
#endif /* DELAY_H_ */
+5 -8
View File
@@ -25,17 +25,15 @@
#include "Object.h" #include "Object.h"
#include "Reference.h" #include "Reference.h"
#include "StringMap.h" #include "StringMap.h"
#include <thread/threads.h>
// STD // STD
#include <iostream> #include <iostream>
// SDL
#include <SDL_mutex.h>
#include <SDL_thread.h>
namespace love namespace love
{ {
static SDL_mutex *gcmutex = 0; static thread::Mutex *gcmutex = 0;
void *_gcmutex = 0; void *_gcmutex = 0;
unsigned int _gcthread = 0; unsigned int _gcthread = 0;
/** /**
@@ -46,17 +44,16 @@ namespace love
{ {
if (!gcmutex) if (!gcmutex)
{ {
gcmutex = SDL_CreateMutex(); gcmutex = new thread::Mutex();
_gcmutex = (void*) gcmutex; _gcmutex = (void*) gcmutex;
} }
Proxy * p = (Proxy *)lua_touserdata(L, 1); Proxy * p = (Proxy *)lua_touserdata(L, 1);
Object * t = (Object *)p->data; Object * t = (Object *)p->data;
if(p->own) if(p->own)
{ {
SDL_mutexP(gcmutex); thread::Lock lock(gcmutex);
_gcthread = (unsigned int) SDL_ThreadID(); _gcthread = thread::ThreadBase::threadId();
t->release(); t->release();
SDL_mutexV(gcmutex);
} }
return 0; return 0;
} }
+2 -2
View File
@@ -52,7 +52,7 @@
#include <physics/box2d/wrap_Physics.h> #include <physics/box2d/wrap_Physics.h>
#include <sound/wrap_Sound.h> #include <sound/wrap_Sound.h>
#include <timer/sdl/wrap_Timer.h> #include <timer/sdl/wrap_Timer.h>
#include <thread/sdl/wrap_Thread.h> #include <thread/wrap_Thread.h>
// Libraries. // Libraries.
#include "libraries/luasocket/luasocket.h" #include "libraries/luasocket/luasocket.h"
@@ -77,7 +77,7 @@ static const luaL_Reg modules[] = {
{ "love.physics", love::physics::box2d::luaopen_love_physics }, { "love.physics", love::physics::box2d::luaopen_love_physics },
{ "love.sound", love::sound::luaopen_love_sound }, { "love.sound", love::sound::luaopen_love_sound },
{ "love.timer", love::timer::sdl::luaopen_love_timer }, { "love.timer", love::timer::sdl::luaopen_love_timer },
{ "love.thread", love::thread::sdl::luaopen_love_thread }, { "love.thread", love::thread::luaopen_love_thread },
{ 0, 0 } { 0, 0 }
}; };
+33 -17
View File
@@ -19,6 +19,7 @@
**/ **/
#include "Audio.h" #include "Audio.h"
#include <common/delay.h>
#include <sound/Decoder.h> #include <sound/Decoder.h>
@@ -28,8 +29,34 @@ namespace audio
{ {
namespace openal namespace openal
{ {
Audio::PoolThread::PoolThread(Pool* pool)
: pool(pool), finish(false) {
}
void Audio::PoolThread::main()
{
while(true) {
{
thread::Lock lock(mutex);
if (finish) {
return;
}
}
pool->update();
delay(5);
}
}
void Audio::PoolThread::setFinish()
{
thread::Lock lock(mutex);
finish = true;
}
Audio::Audio() Audio::Audio()
: finish(false)
{ {
// Passing zero for default device. // Passing zero for default device.
device = alcOpenDevice(0); device = alcOpenDevice(0);
@@ -67,15 +94,16 @@ namespace openal
// pool must be allocated after AL context. // pool must be allocated after AL context.
pool = new Pool(); pool = new Pool();
thread = SDL_CreateThread(Audio::run, (void*)this); poolThread = new PoolThread(pool);
poolThread->start();
} }
Audio::~Audio() Audio::~Audio()
{ {
finish = true; poolThread->setFinish();
poolThread->wait();
SDL_WaitThread(thread, 0);
delete poolThread;
delete pool; delete pool;
alcMakeContextCurrent(0); alcMakeContextCurrent(0);
@@ -84,18 +112,6 @@ namespace openal
alcCloseDevice(device); alcCloseDevice(device);
} }
int Audio::run(void * d)
{
Audio * instance = (Audio*)d;
while(!instance->finish)
{
instance->pool->update();
SDL_Delay(5);
}
return 0;
}
const char * Audio::getName() const const char * Audio::getName() const
{ {
+21 -7
View File
@@ -37,6 +37,7 @@
#include "Source.h" #include "Source.h"
#include "Pool.h" #include "Pool.h"
#include <thread/threads.h>
// OpenAL // OpenAL
#ifdef LOVE_MACOSX #ifdef LOVE_MACOSX
@@ -66,17 +67,30 @@ namespace openal
// The OpenAL context. // The OpenAL context.
ALCcontext * context; ALCcontext * context;
SDL_Thread * thread;
// The Pool. // The Pool.
Pool * pool; Pool * pool;
// Set this to true when the thread should finish.
// Main thread will write to this value, and Audio::run
// will read from it.
bool finish;
static int run(void * unused); class PoolThread: public thread::ThreadBase {
protected:
Pool* pool;
// Set this to true when the thread should finish.
// Main thread will write to this value, and PoolThread
// will read from it.
volatile bool finish;
// finish lock
thread::Mutex mutex;
virtual void main();
public:
PoolThread(Pool* pool);
void setFinish();
};
PoolThread* poolThread;
public: public:
+22 -33
View File
@@ -44,7 +44,7 @@ namespace openal
alGenSources(NUM_SOURCES, sources); alGenSources(NUM_SOURCES, sources);
// Create the mutex. // Create the mutex.
mutex = SDL_CreateMutex(); mutex = new thread::Mutex();
if(alGetError() != AL_NO_ERROR) if(alGetError() != AL_NO_ERROR)
throw love::Exception("Could not generate sources."); throw love::Exception("Could not generate sources.");
@@ -58,7 +58,7 @@ namespace openal
{ {
stop(); stop();
SDL_DestroyMutex(mutex); delete mutex;
// Free all sources. // Free all sources.
alDeleteSources(NUM_SOURCES, sources); alDeleteSources(NUM_SOURCES, sources);
@@ -67,28 +67,30 @@ namespace openal
bool Pool::isAvailable() const bool Pool::isAvailable() const
{ {
bool has = false; bool has = false;
LOCK(mutex); {
has = !available.empty(); thread::Lock lock(mutex);
UNLOCK(mutex); has = !available.empty();
}
return has; return has;
} }
bool Pool::isPlaying(Source * s) bool Pool::isPlaying(Source * s)
{ {
bool p = false; bool p = false;
LOCK(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{ {
if(i->first == s) thread::Lock lock(mutex);
p = true; for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{
if(i->first == s)
p = true;
}
} }
UNLOCK(mutex);
return p; return p;
} }
void Pool::update() void Pool::update()
{ {
LOCK(mutex); thread::Lock lock(mutex);
std::map<Source *, ALuint>::iterator i = playing.begin(); std::map<Source *, ALuint>::iterator i = playing.begin();
@@ -107,8 +109,6 @@ namespace openal
i++; i++;
} }
} }
UNLOCK(mutex);
} }
int Pool::getNumSources() const int Pool::getNumSources() const
@@ -126,7 +126,7 @@ namespace openal
bool ok; bool ok;
out = 0; out = 0;
LOCK(mutex); thread::Lock lock(mutex);
bool alreadyPlaying = findSource(source, out); bool alreadyPlaying = findSource(source, out);
@@ -160,14 +160,12 @@ namespace openal
ok = true; ok = true;
} }
UNLOCK(mutex);
return ok; return ok;
} }
void Pool::stop() void Pool::stop()
{ {
LOCK(mutex); thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++) for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{ {
i->first->stopAtomic(); i->first->stopAtomic();
@@ -175,66 +173,57 @@ namespace openal
} }
playing.clear(); playing.clear();
UNLOCK(mutex);
} }
void Pool::stop(Source * source) void Pool::stop(Source * source)
{ {
LOCK(mutex); thread::Lock lock(mutex);
removeSource(source); removeSource(source);
UNLOCK(mutex);
} }
void Pool::pause() void Pool::pause()
{ {
LOCK(mutex); thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++) for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->pauseAtomic(); i->first->pauseAtomic();
UNLOCK(mutex);
} }
void Pool::pause(Source * source) void Pool::pause(Source * source)
{ {
LOCK(mutex); thread::Lock lock(mutex);
ALuint out; ALuint out;
if(findSource(source, out)) if(findSource(source, out))
source->pauseAtomic(); source->pauseAtomic();
UNLOCK(mutex);
} }
void Pool::resume() void Pool::resume()
{ {
LOCK(mutex); thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++) for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->resumeAtomic(); i->first->resumeAtomic();
UNLOCK(mutex);
} }
void Pool::resume(Source * source) void Pool::resume(Source * source)
{ {
LOCK(mutex); thread::Lock lock(mutex);
ALuint out; ALuint out;
if(findSource(source, out)) if(findSource(source, out))
source->resumeAtomic(); source->resumeAtomic();
UNLOCK(mutex);
} }
void Pool::rewind() void Pool::rewind()
{ {
LOCK(mutex); thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++) for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->rewindAtomic(); i->first->rewindAtomic();
UNLOCK(mutex);
} }
void Pool::rewind(Source * source) void Pool::rewind(Source * source)
{ {
LOCK(mutex); thread::Lock lock(mutex);
ALuint out; ALuint out;
if(findSource(source, out)) if(findSource(source, out))
source->rewindAtomic(); source->rewindAtomic();
UNLOCK(mutex);
} }
void Pool::release(Source * source) void Pool::release(Source * source)
+2 -1
View File
@@ -33,6 +33,7 @@
// LOVE // LOVE
#include <common/config.h> #include <common/config.h>
#include <common/Exception.h> #include <common/Exception.h>
#include <thread/threads.h>
// OpenAL // OpenAL
#ifdef LOVE_MACOSX #ifdef LOVE_MACOSX
@@ -70,7 +71,7 @@ namespace openal
// Only one thread can access this object at the same time. This mutex will // Only one thread can access this object at the same time. This mutex will
// make sure of that. // make sure of that.
SDL_mutex * mutex; thread::Mutex* mutex;
public: public:
@@ -31,10 +31,14 @@ namespace love
{ {
namespace thread namespace thread
{ {
namespace sdl
{ Thread::ThreadThread::ThreadThread(ThreadData* comm)
int threadfunc(ThreadData *comm) : comm(comm)
{ {
}
void Thread::ThreadThread::main() {
lua_State * L = lua_open(); lua_State * L = lua_open();
luaL_openlibs(L); luaL_openlibs(L);
#ifdef LOVE_BUILD_STANDALONE #ifdef LOVE_BUILD_STANDALONE
@@ -53,17 +57,18 @@ namespace sdl
lua_setfield(L, -2, "_curthread"); lua_setfield(L, -2, "_curthread");
if(luaL_dostring(L, comm->getCode()) == 1) if(luaL_dostring(L, comm->getCode()) == 1)
{ {
SDL_mutexP((SDL_mutex*) comm->mutex); {
ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1)); Lock lock((Mutex*) comm->mutex);
comm->setValue("error", v); ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
v->release(); comm->setValue("error", v);
SDL_mutexV((SDL_mutex*) comm->mutex); v->release();
SDL_CondBroadcast((SDL_cond*) comm->cond); }
((Conditional*) comm->cond)->broadcast();
} }
lua_close(L); lua_close(L);
return 0;
} }
ThreadVariant::ThreadVariant(bool boolean) ThreadVariant::ThreadVariant(bool boolean)
{ {
type = BOOLEAN; type = BOOLEAN;
@@ -183,8 +188,8 @@ namespace sdl
this->data = new char[len+1]; this->data = new char[len+1];
memset(this->data, 0, len+1); memset(this->data, 0, len+1);
memcpy(this->data, data->getData(), len); memcpy(this->data, data->getData(), len);
mutex = SDL_CreateMutex(); mutex = new Mutex();
cond = SDL_CreateCond(); cond = new Conditional();
comm = new ThreadData(name.c_str(), name.length(), this->data, mutex, cond); comm = new ThreadData(name.c_str(), name.length(), this->data, mutex, cond);
} }
@@ -192,8 +197,8 @@ namespace sdl
: handle(0), module(module), name(name), data(0), isThread(false) : handle(0), module(module), name(name), data(0), isThread(false)
{ {
module->retain(); module->retain();
mutex = SDL_CreateMutex(); mutex = new Mutex();
cond = SDL_CreateCond(); cond = new Conditional();
comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond); comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond);
} }
@@ -203,25 +208,27 @@ namespace sdl
delete[] data; delete[] data;
delete comm; delete comm;
module->unregister(name); module->unregister(name);
SDL_DestroyMutex(mutex); delete mutex;
SDL_DestroyCond(cond); delete cond;
module->release(); module->release();
} }
void Thread::start() void Thread::start()
{ {
if (!handle && isThread) if (!handle && isThread) {
handle = SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm); handle = new ThreadThread(comm);
handle->start();
}
} }
void Thread::kill() void Thread::kill()
{ {
if (handle) if (handle)
{ {
SDL_mutexP((SDL_mutex *) _gcmutex); Lock lock((Mutex *) _gcmutex);
SDL_KillThread(handle); handle->kill();
delete handle;
handle = 0; handle = 0;
SDL_mutexV((SDL_mutex *) _gcmutex);
} }
} }
@@ -229,19 +236,20 @@ namespace sdl
{ {
if (handle) if (handle)
{ {
SDL_WaitThread(handle, NULL); handle->wait();
delete handle;
handle = 0; handle = 0;
} }
} }
void Thread::lock() void Thread::lock()
{ {
SDL_mutexP(mutex); mutex->lock();
} }
void Thread::unlock() void Thread::unlock()
{ {
SDL_mutexV(mutex); mutex->unlock();
} }
std::string Thread::getName() std::string Thread::getName()
@@ -264,7 +272,7 @@ namespace sdl
{ {
if (comm->getValue("error")) if (comm->getValue("error"))
return 0; return 0;
SDL_CondWait(cond, mutex); cond->wait(mutex);
v = comm->getValue(name); v = comm->getValue(name);
} }
v->retain(); v->retain();
@@ -281,7 +289,7 @@ namespace sdl
lock(); //this function explicitly locks lock(); //this function explicitly locks
comm->setValue(name, v); //because we need comm->setValue(name, v); //because we need
unlock(); //it to unlock here for the cond unlock(); //it to unlock here for the cond
SDL_CondBroadcast(cond); cond->broadcast();
} }
ThreadModule::ThreadModule() ThreadModule::ThreadModule()
@@ -294,6 +302,7 @@ namespace sdl
for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++) for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)
{ {
i->second->kill(); i->second->kill();
delete i->second;
} }
} }
@@ -333,6 +342,7 @@ namespace sdl
if (threads.count(name) == 0) if (threads.count(name) == 0)
return; return;
threadlist_t::iterator i = threads.find(name); threadlist_t::iterator i = threads.find(name);
// FIXME: shouldn't the thread be deleted?
threads.erase(i); threads.erase(i);
} }
@@ -340,6 +350,6 @@ namespace sdl
{ {
return "love.thread.sdl"; return "love.thread.sdl";
} }
} // sdl
} // thread } // thread
} // love } // love
@@ -21,25 +21,24 @@
#ifndef LOVE_THREAD_SDL_THREAD_H #ifndef LOVE_THREAD_SDL_THREAD_H
#define LOVE_THREAD_SDL_THREAD_H #define LOVE_THREAD_SDL_THREAD_H
// SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
// STL // STL
#include <map> #include <map>
#include <string> #include <string>
// LOVE // LOVE
#include <thread/ThreadModule.h>
#include <filesystem/File.h> #include <filesystem/File.h>
#include <common/runtime.h> #include <common/runtime.h>
#include <common/Module.h>
#include <thread/threads.h>
namespace love namespace love
{ {
namespace thread namespace thread
{ {
namespace sdl
{ class ThreadModule;
enum ThreadVariantType enum ThreadVariantType
{ {
UNKNOWN = 0, UNKNOWN = 0,
@@ -98,15 +97,28 @@ namespace sdl
class Thread : public love::Object class Thread : public love::Object
{ {
private: private:
SDL_Thread *handle; class ThreadThread: public ThreadBase {
love::thread::ThreadModule *module; private:
ThreadData* comm;
protected:
virtual void main();
public:
ThreadThread(ThreadData* comm);
};
ThreadThread *handle;
ThreadModule *module;
ThreadData *comm; ThreadData *comm;
std::string name; std::string name;
char *data; char *data;
SDL_mutex *mutex; Mutex *mutex;
SDL_cond *cond; Conditional *cond;
bool isThread; bool isThread;
public: public:
Thread(love::thread::ThreadModule *module, const std::string & name, love::Data *data); Thread(love::thread::ThreadModule *module, const std::string & name, love::Data *data);
Thread(love::thread::ThreadModule *module, const std::string & name); Thread(love::thread::ThreadModule *module, const std::string & name);
@@ -125,7 +137,7 @@ namespace sdl
typedef std::map<std::string, Thread*> threadlist_t; typedef std::map<std::string, Thread*> threadlist_t;
class ThreadModule : public love::thread::ThreadModule class ThreadModule : public love::Module
{ {
private: private:
threadlist_t threads; threadlist_t threads;
@@ -140,7 +152,6 @@ namespace sdl
void unregister(const std::string & name); void unregister(const std::string & name);
const char *getName() const; const char *getName() const;
}; // ThreadModule }; // ThreadModule
} // sdl
} // thread } // thread
} // love } // love
+196
View File
@@ -0,0 +1,196 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "threads.h"
namespace love
{
namespace thread
{
Mutex::Mutex() {
pthread_create_mutex(&mutex, NULL);
}
Mutex::~Mutex() {
pthread_mutex_destroy(&mutex);
}
void Mutex::lock() {
pthread_mutex_lock(&mutex);
}
void Mutex::unlock() {
pthread_mutex_unlock(&mutex);
}
void* ThreadBase::thread_runner(void* param) {
ThreadBase* thread = (ThreadBase*)param;
thread->main();
return NULL;
}
ThreadBase::ThreadBase() : running(false) {
pthread_t thread;
}
ThreadBase::~ThreadBase() {
if (running) {
wait();
}
}
bool ThreadBase::start() {
if (pthread_create(&thread, NULL, thread_runner, this)) {
return false;
} else {
running = true;
return true;
}
}
void ThreadBase::wait() {
pthread_join(thread, NULL);
running = false;
}
void ThreadBase::kill() {
// FIXME: I'm not sure about that one.
pthread_kill(thread, 9);
running = false;
}
unsigned int ThreadBase::threadId() {
return (unsigned int)((size_t)pthread_self());
}
Semaphore::Semaphore(unsigned int initial_value) {
sem_init(&sem, 0, initial_value);
}
Semaphore::~Semaphore() {
sem_destroy(&sem);
}
unsigned int Semaphore::value() {
int val = 0;
if (sem_getvalue(&sem, &val)) {
return 0;
} else {
return val;
}
}
void Semaphore::post() {
sem_post(&sem);
}
bool Semaphore::wait(int timeout) {
if (timeout < 0) {
if (sem_wait(&sem)) {
return false;
} else {
return true;
}
} else if (timeout == 0) {
if (sem_trywait(&sem)) {
return false;
} else {
return true;
}
} else {
struct timespec ts;
ts.tv_sec = timeout/1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
if (sem_timedwait(&sem, &ts)) {
return false; // either timeout or error...
} else {
return true;
}
}
}
bool Semaphore::tryWait() {
if (sem_trywait(&sem)) {
return false;
} else {
return true;
}
}
Conditional::Conditional() {
pthread_cond_init(&cond, NULL);
}
Conditional::~Conditional() {
pthread_cond_destroy(&cond);
}
void Conditional::signal() {
pthread_cond_signal(&cond);
}
void Conditional::broadcast() {
pthread_cond_broadcast(&cond);
}
bool Conditional::wait(Mutex* mutex, int timeout) {
if (timeout < 0) {
if (pthread_cond_wait(cond, mutex->mutex)) {
return false;
} else {
return true;
}
} else {
struct timespec ts;
int ret;
ts.tv_sec = timeout / 1000;
ts.tv_nsec = (timeout % 1000) * 1000000;
ret = pthread_cond_timedwait(&cond, mutex->mutex, &ts);
if (ret == ETIMEDOUT) {
return false;
} else if (ret == 0) {
return true;
} else {
// something bad happend!
return false;
}
}
}
} // namespace thread
} // namespace love
+103
View File
@@ -0,0 +1,103 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_PLATFORM_POSIX_THREADS_H_
#define LOVE_PLATFORM_POSIX_THREADS_H_
#include <pthread.h>
#include <semaphore.h>
namespace love
{
namespace thread
{
class Mutex {
private:
pthread_mutex_t mutex;
Mutex(const Mutex& mutex) {}
friend class Conditional;
public:
Mutex();
~Mutex();
void lock();
void unlock();
};
class ThreadBase {
private:
pthread_t thread;
ThreadBase(ThreadBase& thread) {}
static void* thread_runner(void* param);
protected:
virtual void main() = 0;
public:
ThreadBase();
virtual ~ThreadBase();
bool start();
void wait();
void kill();
static unsigned int threadId();
};
class Semaphore {
private:
Semaphore(const Semaphore& sem) {}
sem_t semaphore;
public:
Semaphore(unsigned int initial_value);
~Semaphore();
unsigned int value();
void post();
bool wait(int timeout = -1);
bool tryWait();
};
// Should conditional inherit from mutex?
class Conditional {
private:
pthread_cond_t cond;
public:
Conditional();
~Conditional();
void signal();
void broadcast();
bool wait(Mutex* mutex, int timeout=-1);
};
} // namespace thread
} // namespace love
#endif // !LOVE_PLATFORM_POSIX_THREADS_H_
+164
View File
@@ -0,0 +1,164 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "threads.h"
namespace love
{
namespace thread
{
Mutex::Mutex() {
mutex = SDL_CreateMutex();
}
Mutex::~Mutex() {
SDL_DestroyMutex(mutex);
}
void Mutex::lock() {
SDL_mutexP(mutex);
}
void Mutex::unlock() {
SDL_mutexV(mutex);
}
int ThreadBase::thread_runner(void* param) {
ThreadBase* thread = (ThreadBase*)param;
thread->main();
return 0;
}
ThreadBase::ThreadBase() : running(false) {
SDL_Thread* thread;
}
ThreadBase::~ThreadBase() {
if (running) {
wait();
}
}
bool ThreadBase::start() {
thread = SDL_CreateThread(thread_runner, this);
if (thread == NULL) {
return false;
} else {
running = true;
return true;
}
}
void ThreadBase::wait() {
SDL_WaitThread(thread, NULL);
running = false;
}
void ThreadBase::kill() {
SDL_KillThread(thread);
running = false;
}
unsigned int ThreadBase::threadId() {
return (unsigned int)SDL_ThreadID();
}
Semaphore::Semaphore(unsigned int initial_value) {
semaphore = SDL_CreateSemaphore(initial_value);
}
Semaphore::~Semaphore() {
SDL_DestroySemaphore(semaphore);
}
unsigned int Semaphore::value() {
return SDL_SemValue(semaphore);
}
void Semaphore::post() {
SDL_SemPost(semaphore);
}
bool Semaphore::wait(int timeout) {
if (timeout < 0) {
return SDL_SemWait(semaphore) ? false : true;
} else if (timeout == 0) {
return SDL_SemTryWait(semaphore) ? false : true;
} else {
int ret = SDL_SemWaitTimeout(semaphore, timeout);
if (ret == SDL_MUTEX_TIMEDOUT) {
return false;
} else if (ret == 0) {
return true;
} else {
// some nasty error
return false;
}
}
}
bool Semaphore::tryWait() {
return SDL_SemTryWait(semaphore) ? false : true;
}
Conditional::Conditional() {
cond = SDL_CreateCond();
}
Conditional::~Conditional() {
SDL_DestroyCond(cond);
}
void Conditional::signal() {
SDL_CondSignal(cond);
}
void Conditional::broadcast() {
SDL_CondBroadcast(cond);
}
bool Conditional::wait(Mutex* mutex, int timeout) {
if (timeout < 0) {
if (SDL_CondWait(cond, mutex->mutex)) {
// error
return false;
} else {
return true;
}
} else {
int ret = SDL_CondWaitTimeout(cond, mutex->mutex, timeout);
if (ret == SDL_MUTEX_TIMEDOUT) {
return false;
} else if (ret == 0) {
return true;
} else {
// some bad error
return false;
}
}
}
} // namespace thread
} // namespace love
+104
View File
@@ -0,0 +1,104 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_PLATFORM_SDL_THREADS_H_
#define LOVE_PLATFORM_SDL_THREADS_H_
#include "SDL.h"
namespace love
{
namespace thread
{
class Mutex {
private:
SDL_mutex* mutex;
Mutex(const Mutex& mutex) {}
friend class Conditional;
public:
Mutex();
~Mutex();
void lock();
void unlock();
};
class ThreadBase {
private:
SDL_Thread* thread;
ThreadBase(ThreadBase& thread) {}
bool running;
static int thread_runner(void* param);
protected:
virtual void main() = 0;
public:
ThreadBase();
virtual ~ThreadBase();
bool start();
void wait();
void kill(); // FIXME: not supported by SDL (SDL's kill is probably cancel)?
static unsigned int threadId();
};
class Semaphore {
private:
Semaphore(const Semaphore& sem) {}
SDL_sem* semaphore;
public:
Semaphore(unsigned int initial_value);
~Semaphore();
unsigned int value();
void post();
bool wait(int timeout = -1);
bool tryWait();
};
// Should conditional inherit from mutex?
class Conditional {
private:
SDL_cond* cond;
public:
Conditional();
~Conditional();
void signal();
void broadcast();
bool wait(Mutex* mutex, int timeout=-1);
};
} // namespace thread
} // namespace love
#endif // !LOVE_PLATFORM_SDL_THREADS_H_
+49
View File
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "threads.h"
#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() {
#if LOVE_THREADS == LOVE_THREADS_POSIX
return "posix";
#elif LOVE_THREADS == LOVE_THREADS_WIN32
return "win32";
#elif LOVE_THREADS == LOVE_THREADS_SDL
return "sdl";
#else
return "unknown"; // ?!?!?!
#endif
}
} // namespace thread
} // namespace love
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_THREADS_H_
#define LOVE_THREADS_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
namespace love
{
namespace thread
{
const char* threadAPI();
class Lock {
private:
Mutex* mutex;
Lock(Lock& lock) {}
public:
Lock(Mutex* m): mutex(m) {
mutex->lock();
}
Lock(Mutex& m): mutex(&m) {
mutex->lock();
}
~Lock() {
mutex->unlock();
}
};
} // namespace thread
} // namespace love
#endif /* LOVE_THREADS_H_ */
+202
View File
@@ -0,0 +1,202 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "threads.h"
namespace love
{
namespace thread
{
Mutex::Mutex() {
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) {
HANDLE thread;
}
ThreadBase::~ThreadBase() {
if (running) {
wait();
}
}
bool ThreadBase::start() {
thread = CreateThread(NULL, 0, run_thread, rd, NULL);
if (thread == NULL) {
return false;
} else {
running = true;
return 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, 65535, 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 if (result == WAIT_TIMEOUT) {
return false;
} else {
// error
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();
}
} // namespace thread
} // namespace love
+106
View File
@@ -0,0 +1,106 @@
/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_PLATFROM_WIN32_THREADS_H_
#define LOVE_PLATFROM_WIN32_THREADS_H_
#include <windows.h>
namespace love
{
namespace thread
{
class Mutex {
private:
CRITICAL_SECTION mutex;
Mutex(const Mutex& mutex) {}
public:
Mutex();
~Mutex();
void lock();
void unlock();
};
class ThreadBase {
private:
HANDLE thread;
ThreadBase(ThreadBase& thread) {}
bool running;
static int thread_runner(void* param);
protected:
virtual void main() = 0;
public:
ThreadBase();
virtual ~ThreadBase();
bool start();
void wait();
void kill();
static unsigned int threadId();
};
class Semaphore {
private:
Semaphore(const Semaphore& sem) {}
HANDLE semaphore;
unsigned int count;
public:
Semaphore(unsigned int initial_value);
~Semaphore();
unsigned int value();
void post();
bool wait(int timeout = -1);
bool tryWait();
};
// Should conditional inherit from mutex?
class Conditional {
private:
Mutex mutex;
int waiting;
int signals;
Semaphore sem;
Semaphore done;
public:
Conditional();
~Conditional();
void signal();
void broadcast();
bool wait(Mutex* cmutex, int timeout=-1);
};
} // namespace thread
} // namespace love
#endif /* LOVE_PLATFROM_WIN32_THREADS_H_ */
@@ -35,8 +35,6 @@ namespace
namespace love namespace love
{ {
namespace thread namespace thread
{
namespace sdl
{ {
Thread *luax_checkthread(lua_State *L, int idx) Thread *luax_checkthread(lua_State *L, int idx)
{ {
@@ -390,4 +388,3 @@ namespace sdl
} }
} }
} }
}
@@ -29,8 +29,6 @@ namespace love
{ {
extern StringMap<Type, TYPE_MAX_ENUM> types; extern StringMap<Type, TYPE_MAX_ENUM> types;
namespace thread namespace thread
{
namespace sdl
{ {
Thread *luax_checkthread(lua_State *L, int idx); Thread *luax_checkthread(lua_State *L, int idx);
int w_Thread_start(lua_State *L); int w_Thread_start(lua_State *L);
@@ -49,7 +47,7 @@ namespace sdl
int w_getThread(lua_State *L); int w_getThread(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State * L); extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State * L);
} // sdl
} // thread } // thread
} // love } // love
+2 -1
View File
@@ -19,6 +19,7 @@
**/ **/
#include <common/config.h> #include <common/config.h>
#include <common/delay.h>
#ifdef LOVE_WINDOWS #ifdef LOVE_WINDOWS
# include <windows.h> # include <windows.h>
@@ -81,7 +82,7 @@ namespace sdl
void Timer::sleep(int ms) void Timer::sleep(int ms)
{ {
if(ms > 0) if(ms > 0)
SDL_Delay(ms); delay(ms);
} }
float Timer::getDelta() const float Timer::getDelta() const