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
+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.
**/
#ifndef LOVE_THREAD_THREAD_H
#define LOVE_THREAD_THREAD_H
#ifndef DELAY_H_
#define DELAY_H_
#include <common/Module.h>
#include <string>
#include <thread/threads.h>
namespace love
{
namespace thread
{
class ThreadModule : public Module
{
public:
virtual ~ThreadModule(){};
virtual void unregister(const std::string & name) = 0;
}; // ThreadModule
} // thread
} // love
namespace 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 "Reference.h"
#include "StringMap.h"
#include <thread/threads.h>
// STD
#include <iostream>
// SDL
#include <SDL_mutex.h>
#include <SDL_thread.h>
namespace love
{
static SDL_mutex *gcmutex = 0;
static thread::Mutex *gcmutex = 0;
void *_gcmutex = 0;
unsigned int _gcthread = 0;
/**
@@ -46,17 +44,16 @@ namespace love
{
if (!gcmutex)
{
gcmutex = SDL_CreateMutex();
gcmutex = new thread::Mutex();
_gcmutex = (void*) gcmutex;
}
Proxy * p = (Proxy *)lua_touserdata(L, 1);
Object * t = (Object *)p->data;
if(p->own)
{
SDL_mutexP(gcmutex);
_gcthread = (unsigned int) SDL_ThreadID();
thread::Lock lock(gcmutex);
_gcthread = thread::ThreadBase::threadId();
t->release();
SDL_mutexV(gcmutex);
}
return 0;
}
+2 -2
View File
@@ -52,7 +52,7 @@
#include <physics/box2d/wrap_Physics.h>
#include <sound/wrap_Sound.h>
#include <timer/sdl/wrap_Timer.h>
#include <thread/sdl/wrap_Thread.h>
#include <thread/wrap_Thread.h>
// Libraries.
#include "libraries/luasocket/luasocket.h"
@@ -77,7 +77,7 @@ static const luaL_Reg modules[] = {
{ "love.physics", love::physics::box2d::luaopen_love_physics },
{ "love.sound", love::sound::luaopen_love_sound },
{ "love.timer", love::timer::sdl::luaopen_love_timer },
{ "love.thread", love::thread::sdl::luaopen_love_thread },
{ "love.thread", love::thread::luaopen_love_thread },
{ 0, 0 }
};
+33 -17
View File
@@ -19,6 +19,7 @@
**/
#include "Audio.h"
#include <common/delay.h>
#include <sound/Decoder.h>
@@ -28,8 +29,34 @@ namespace audio
{
namespace openal
{
Audio::PoolThread::PoolThread(Pool* pool)
: pool(pool), finish(false) {
}
void Audio::PoolThread::main()
{
while(true) {
{
thread::Lock lock(mutex);
if (finish) {
return;
}
}
pool->update();
delay(5);
}
}
void Audio::PoolThread::setFinish()
{
thread::Lock lock(mutex);
finish = true;
}
Audio::Audio()
: finish(false)
{
// Passing zero for default device.
device = alcOpenDevice(0);
@@ -67,15 +94,16 @@ namespace openal
// pool must be allocated after AL context.
pool = new Pool();
thread = SDL_CreateThread(Audio::run, (void*)this);
poolThread = new PoolThread(pool);
poolThread->start();
}
Audio::~Audio()
{
finish = true;
SDL_WaitThread(thread, 0);
poolThread->setFinish();
poolThread->wait();
delete poolThread;
delete pool;
alcMakeContextCurrent(0);
@@ -84,18 +112,6 @@ namespace openal
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
{
+21 -7
View File
@@ -37,6 +37,7 @@
#include "Source.h"
#include "Pool.h"
#include <thread/threads.h>
// OpenAL
#ifdef LOVE_MACOSX
@@ -66,17 +67,30 @@ namespace openal
// The OpenAL context.
ALCcontext * context;
SDL_Thread * thread;
// The Pool.
Pool * pool;
// Set this to true when the thread should finish.
// Main thread will write to this value, and Audio::run
// will read from it.
bool finish;
static int run(void * unused);
class PoolThread: public thread::ThreadBase {
protected:
Pool* pool;
// Set this to true when the thread should finish.
// Main thread will write to this value, and PoolThread
// will read from it.
volatile bool finish;
// finish lock
thread::Mutex mutex;
virtual void main();
public:
PoolThread(Pool* pool);
void setFinish();
};
PoolThread* poolThread;
public:
+22 -33
View File
@@ -44,7 +44,7 @@ namespace openal
alGenSources(NUM_SOURCES, sources);
// Create the mutex.
mutex = SDL_CreateMutex();
mutex = new thread::Mutex();
if(alGetError() != AL_NO_ERROR)
throw love::Exception("Could not generate sources.");
@@ -58,7 +58,7 @@ namespace openal
{
stop();
SDL_DestroyMutex(mutex);
delete mutex;
// Free all sources.
alDeleteSources(NUM_SOURCES, sources);
@@ -67,28 +67,30 @@ namespace openal
bool Pool::isAvailable() const
{
bool has = false;
LOCK(mutex);
has = !available.empty();
UNLOCK(mutex);
{
thread::Lock lock(mutex);
has = !available.empty();
}
return has;
}
bool Pool::isPlaying(Source * s)
{
bool p = false;
LOCK(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{
if(i->first == s)
p = true;
thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{
if(i->first == s)
p = true;
}
}
UNLOCK(mutex);
return p;
}
void Pool::update()
{
LOCK(mutex);
thread::Lock lock(mutex);
std::map<Source *, ALuint>::iterator i = playing.begin();
@@ -107,8 +109,6 @@ namespace openal
i++;
}
}
UNLOCK(mutex);
}
int Pool::getNumSources() const
@@ -126,7 +126,7 @@ namespace openal
bool ok;
out = 0;
LOCK(mutex);
thread::Lock lock(mutex);
bool alreadyPlaying = findSource(source, out);
@@ -160,14 +160,12 @@ namespace openal
ok = true;
}
UNLOCK(mutex);
return ok;
}
void Pool::stop()
{
LOCK(mutex);
thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
{
i->first->stopAtomic();
@@ -175,66 +173,57 @@ namespace openal
}
playing.clear();
UNLOCK(mutex);
}
void Pool::stop(Source * source)
{
LOCK(mutex);
thread::Lock lock(mutex);
removeSource(source);
UNLOCK(mutex);
}
void Pool::pause()
{
LOCK(mutex);
thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->pauseAtomic();
UNLOCK(mutex);
}
void Pool::pause(Source * source)
{
LOCK(mutex);
thread::Lock lock(mutex);
ALuint out;
if(findSource(source, out))
source->pauseAtomic();
UNLOCK(mutex);
}
void Pool::resume()
{
LOCK(mutex);
thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->resumeAtomic();
UNLOCK(mutex);
}
void Pool::resume(Source * source)
{
LOCK(mutex);
thread::Lock lock(mutex);
ALuint out;
if(findSource(source, out))
source->resumeAtomic();
UNLOCK(mutex);
}
void Pool::rewind()
{
LOCK(mutex);
thread::Lock lock(mutex);
for(std::map<Source *, ALuint>::iterator i = playing.begin(); i != playing.end(); i++)
i->first->rewindAtomic();
UNLOCK(mutex);
}
void Pool::rewind(Source * source)
{
LOCK(mutex);
thread::Lock lock(mutex);
ALuint out;
if(findSource(source, out))
source->rewindAtomic();
UNLOCK(mutex);
}
void Pool::release(Source * source)
+2 -1
View File
@@ -33,6 +33,7 @@
// LOVE
#include <common/config.h>
#include <common/Exception.h>
#include <thread/threads.h>
// OpenAL
#ifdef LOVE_MACOSX
@@ -70,7 +71,7 @@ namespace openal
// Only one thread can access this object at the same time. This mutex will
// make sure of that.
SDL_mutex * mutex;
thread::Mutex* mutex;
public:
@@ -31,10 +31,14 @@ namespace love
{
namespace thread
{
namespace sdl
{
int threadfunc(ThreadData *comm)
Thread::ThreadThread::ThreadThread(ThreadData* comm)
: comm(comm)
{
}
void Thread::ThreadThread::main() {
lua_State * L = lua_open();
luaL_openlibs(L);
#ifdef LOVE_BUILD_STANDALONE
@@ -53,17 +57,18 @@ namespace sdl
lua_setfield(L, -2, "_curthread");
if(luaL_dostring(L, comm->getCode()) == 1)
{
SDL_mutexP((SDL_mutex*) comm->mutex);
ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
comm->setValue("error", v);
v->release();
SDL_mutexV((SDL_mutex*) comm->mutex);
SDL_CondBroadcast((SDL_cond*) comm->cond);
{
Lock lock((Mutex*) comm->mutex);
ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
comm->setValue("error", v);
v->release();
}
((Conditional*) comm->cond)->broadcast();
}
lua_close(L);
return 0;
}
ThreadVariant::ThreadVariant(bool boolean)
{
type = BOOLEAN;
@@ -183,8 +188,8 @@ namespace sdl
this->data = new char[len+1];
memset(this->data, 0, len+1);
memcpy(this->data, data->getData(), len);
mutex = SDL_CreateMutex();
cond = SDL_CreateCond();
mutex = new Mutex();
cond = new Conditional();
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)
{
module->retain();
mutex = SDL_CreateMutex();
cond = SDL_CreateCond();
mutex = new Mutex();
cond = new Conditional();
comm = new ThreadData(name.c_str(), name.length(), NULL, mutex, cond);
}
@@ -203,25 +208,27 @@ namespace sdl
delete[] data;
delete comm;
module->unregister(name);
SDL_DestroyMutex(mutex);
SDL_DestroyCond(cond);
delete mutex;
delete cond;
module->release();
}
void Thread::start()
{
if (!handle && isThread)
handle = SDL_CreateThread((int (*)(void*)) threadfunc, (void*) comm);
if (!handle && isThread) {
handle = new ThreadThread(comm);
handle->start();
}
}
void Thread::kill()
{
if (handle)
{
SDL_mutexP((SDL_mutex *) _gcmutex);
SDL_KillThread(handle);
Lock lock((Mutex *) _gcmutex);
handle->kill();
delete handle;
handle = 0;
SDL_mutexV((SDL_mutex *) _gcmutex);
}
}
@@ -229,19 +236,20 @@ namespace sdl
{
if (handle)
{
SDL_WaitThread(handle, NULL);
handle->wait();
delete handle;
handle = 0;
}
}
void Thread::lock()
{
SDL_mutexP(mutex);
mutex->lock();
}
void Thread::unlock()
{
SDL_mutexV(mutex);
mutex->unlock();
}
std::string Thread::getName()
@@ -264,7 +272,7 @@ namespace sdl
{
if (comm->getValue("error"))
return 0;
SDL_CondWait(cond, mutex);
cond->wait(mutex);
v = comm->getValue(name);
}
v->retain();
@@ -281,7 +289,7 @@ namespace sdl
lock(); //this function explicitly locks
comm->setValue(name, v); //because we need
unlock(); //it to unlock here for the cond
SDL_CondBroadcast(cond);
cond->broadcast();
}
ThreadModule::ThreadModule()
@@ -294,6 +302,7 @@ namespace sdl
for (threadlist_t::iterator i = threads.begin(); i != threads.end(); i++)
{
i->second->kill();
delete i->second;
}
}
@@ -333,6 +342,7 @@ namespace sdl
if (threads.count(name) == 0)
return;
threadlist_t::iterator i = threads.find(name);
// FIXME: shouldn't the thread be deleted?
threads.erase(i);
}
@@ -340,6 +350,6 @@ namespace sdl
{
return "love.thread.sdl";
}
} // sdl
} // thread
} // love
@@ -21,25 +21,24 @@
#ifndef LOVE_THREAD_SDL_THREAD_H
#define LOVE_THREAD_SDL_THREAD_H
// SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
// STL
#include <map>
#include <string>
// LOVE
#include <thread/ThreadModule.h>
#include <filesystem/File.h>
#include <common/runtime.h>
#include <common/Module.h>
#include <thread/threads.h>
namespace love
{
namespace thread
{
namespace sdl
{
class ThreadModule;
enum ThreadVariantType
{
UNKNOWN = 0,
@@ -98,15 +97,28 @@ namespace sdl
class Thread : public love::Object
{
private:
SDL_Thread *handle;
love::thread::ThreadModule *module;
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;
SDL_mutex *mutex;
SDL_cond *cond;
Mutex *mutex;
Conditional *cond;
bool isThread;
public:
Thread(love::thread::ThreadModule *module, const std::string & name, love::Data *data);
Thread(love::thread::ThreadModule *module, const std::string & name);
@@ -125,7 +137,7 @@ namespace sdl
typedef std::map<std::string, Thread*> threadlist_t;
class ThreadModule : public love::thread::ThreadModule
class ThreadModule : public love::Module
{
private:
threadlist_t threads;
@@ -140,7 +152,6 @@ namespace sdl
void unregister(const std::string & name);
const char *getName() const;
}; // ThreadModule
} // sdl
} // thread
} // 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 thread
{
namespace sdl
{
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;
namespace thread
{
namespace sdl
{
Thread *luax_checkthread(lua_State *L, int idx);
int w_Thread_start(lua_State *L);
@@ -49,7 +47,7 @@ namespace sdl
int w_getThread(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_thread(lua_State * L);
} // sdl
} // thread
} // love
+2 -1
View File
@@ -19,6 +19,7 @@
**/
#include <common/config.h>
#include <common/delay.h>
#ifdef LOVE_WINDOWS
# include <windows.h>
@@ -81,7 +82,7 @@ namespace sdl
void Timer::sleep(int ms)
{
if(ms > 0)
SDL_Delay(ms);
delay(ms);
}
float Timer::getDelta() const