Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None
diff --git a/util/nacl/module.cpp b/util/nacl/module.cpp
index 0b242894..028dd3a3 100644
--- a/util/nacl/module.cpp
+++ b/util/nacl/module.cpp
@@ -1,122 +1,131 @@
#ifdef NACL
/* talks to chrome via the nacl stuff */
#include <ppapi/cpp/instance.h>
#include <ppapi/cpp/module.h>
+// #include <ppapi/cpp/url_loader.h>
#include <ppapi/cpp/var.h>
#include <ppapi/cpp/dev/scriptable_object_deprecated.h>
#include <SDL/SDL.h>
#include <SDL/SDL_nacl.h>
#include <string>
#include "../../main.h"
#include "network-system.h"
#include "../funcs.h"
namespace nacl{
class PaintownScript: public pp::deprecated::ScriptableObject {
public:
virtual bool HasMethod(const pp::Var& method, pp::Var* exception);
virtual pp::Var Call(const pp::Var& method, const std::vector<pp::Var>& args,pp::Var* exception);
};
class PaintownInstance : public pp::Instance {
public:
- explicit PaintownInstance(PP_Instance instance) : pp::Instance(instance) {
+ explicit PaintownInstance(PP_Instance instance, pp::Core * core):
+ pp::Instance(instance),
+ core(core){
the_instance = this;
}
virtual ~PaintownInstance() {}
static PaintownInstance * the_instance;
+ pp::Core * core;
static int launch(void * arg){
int argc = 1;
char * argv[1] = {"paintown"};
Global::debug(0) << "Run paintown main" << std::endl;
paintown_main(argc, argv);
return 0;
}
/* set up the viewport and run the game as usual */
void run(){
+
+ /* forces the url loader interface to be loaded in the browser */
+ // pp::URLLoader notNeeded(this);
+ // Global::debug(0) << "PPB_URLLoader;0.1 = " << pp::Module::Get()->GetBrowserInterface("PPB_URLLoader;0.1") << std::endl;
+
SDL_NACL_SetInstance(pp_instance(), 640, 480);
int ok = SDL_Init(SDL_INIT_VIDEO |
SDL_INIT_AUDIO |
SDL_INIT_TIMER |
SDL_INIT_JOYSTICK |
SDL_INIT_NOPARACHUTE);
Global::debug(0) << "SDL Init: " << ok << std::endl;
// Util::setDataPath("http://localhost:5103/data/");
- Nacl::NetworkSystem * system = new Nacl::NetworkSystem("http://localhost:5103/", this);
+ Nacl::NetworkSystem * system = new Nacl::NetworkSystem("http://localhost:5103/", the_instance, core);
Storage::setInstance(system);
Util::Thread::Id thread;
- Util::Thread::createThread(&thread, NULL, launch, NULL);
+ Util::Thread::createThread(&thread, NULL, (Util::Thread::ThreadFunction) launch, NULL);
Global::debug(0) << "Running thread " << thread << std::endl;
// Global::debug(0) << "Run thread " << Util::Thread::createThread(&thread, NULL, launch, NULL) << std::endl;
- system->run();
+ // system->run();
}
virtual pp::Var GetInstanceObject(){
PaintownScript * object = new PaintownScript();
return pp::Var(this, object);
}
/* when the browser does paintownModule.postMessage('run') this will
* get executed.
*/
virtual void HandleMessage(const pp::Var& var_message){
if (!var_message.is_string()){
return;
}
std::string message = var_message.AsString();
if (message == "run"){
run();
}
}
};
PaintownInstance * PaintownInstance::the_instance;
bool PaintownScript::HasMethod(const pp::Var& method, pp::Var* exception){
if (!method.is_string()){
return false;
}
std::string name = method.AsString();
if (name == "run"){
return true;
}
return false;
}
pp::Var PaintownScript::Call(const pp::Var& method, const std::vector<pp::Var>& args,pp::Var* exception){
if (!method.is_string()){
return false;
}
std::string name = method.AsString();
if (name == "run"){
PaintownInstance::the_instance->run();
}
return pp::Var();
}
class PaintownModule : public pp::Module {
public:
PaintownModule() : pp::Module() {}
virtual ~PaintownModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
- return new PaintownInstance(instance);
+ return new PaintownInstance(instance, core());
}
};
}
namespace pp{
Module * CreateModule(){
return new nacl::PaintownModule();
}
}
#endif
diff --git a/util/nacl/network-system.cpp b/util/nacl/network-system.cpp
index 9bb44724..5fdacdf5 100644
--- a/util/nacl/network-system.cpp
+++ b/util/nacl/network-system.cpp
@@ -1,293 +1,329 @@
#ifdef NACL
/* documentation for ppapi
* http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/inherits.html
*/
/* issues with getting data
* 1. the function that starts the game is called from the main chrome thread
* which starts from a javascript call to module.PostMessage('run').
* ...
*
*/
#include "network-system.h"
#include "../funcs.h"
#include "../debug.h"
#include <ppapi/c/pp_errors.h>
#include <ppapi/cpp/url_loader.h>
#include <ppapi/cpp/url_request_info.h>
#include <ppapi/cpp/completion_callback.h>
using std::string;
namespace Nacl{
typedef Path::AbsolutePath AbsolutePath;
typedef Path::RelativePath RelativePath;
enum RequestType{
Exists
};
struct Request{
RequestType type;
AbsolutePath absolute;
RelativePath relative;
bool complete;
bool success;
};
Request operation;
struct NaclRequest{
virtual ~NaclRequest(){
}
- virtual void start(pp::CompletionCallback callback) = 0;
+ virtual void start(pp::CompletionCallback callback, pp::Core * core) = 0;
};
struct NaclRequestOpen: public NaclRequest {
NaclRequestOpen(pp::Instance * instance, const string & url):
request(instance),
loader(instance){
request.SetURL(url);
request.SetMethod("GET");
}
- void start(pp::CompletionCallback callback){
+ void start(pp::CompletionCallback callback, pp::Core * core){
Global::debug(0) << "Request open" << std::endl;
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
+ // Global::debug(0) << "Call on main thread" << std::endl;
+ // core->CallOnMainThread(0, callback, ok);
callback.Run(ok);
}
Global::debug(0) << "Callback running" << std::endl;
}
pp::URLRequestInfo request;
pp::URLLoader loader;
};
class Manager{
public:
- Manager(pp::Instance * instance, Util::Thread::LockObject & portal):
+ Manager(pp::Instance * instance, pp::Core * core, Util::Thread::LockObject & portal):
instance(instance),
+ core(core),
portal(portal),
- factory(this){
+ factory(NULL){
}
pp::Instance * instance;
+ pp::Core * core;
Util::Thread::LockObject & portal;
Util::ReferenceCount<NaclRequest> request;
- pp::CompletionCallbackFactory<Manager> factory;
+ pp::CompletionCallbackFactory<Manager> * factory;
/*
void start(){
pp::CompletionCallback callback = factory.NewCallback(&Manager::OnOpen);
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
Global::debug(0) << "Callback running" << std::endl;
}
*/
+ static void doStartOpen(void * self, int32_t result){
+ Manager * me = (Manager*) self;
+ me->start();
+ }
+
+ void start(){
+ factory = new pp::CompletionCallbackFactory<Manager>(this);
+ request = new NaclRequestOpen(instance, operation.absolute.path());
+ pp::CompletionCallback callback(&Manager::doOnOpen, this);
+ request->start(callback, core);
+ }
+
+ static void doOnOpen(void * self, int32_t result){
+ Manager * me = (Manager*) self;
+ me->OnOpen(result);
+ }
+
void OnOpen(int32_t response){
if (response == 0){
Global::debug(0) << "Opened!" << std::endl;
operation.success = true;
} else {
- Global::debug(0) << "Failed to open :(" << std::endl;
+ Global::debug(0) << "Failed to open :( " << response << std::endl;
operation.success = false;
}
run2();
}
- void doit(){
+ void run(){
Global::debug(0) << "Requesting a file operation" << std::endl;
-
- request = new NaclRequestOpen(instance, operation.absolute.path());
- Global::debug(0) << "Made request" << std::endl;
- request->start(factory.NewCallback(&Manager::OnOpen));
+
+ // Global::debug(0) << "PPB_URLLoader;0.1 = " << pp::Module::Get()->GetBrowserInterface("PPB_URLLoader;0.1") << std::endl;
+
+ Global::debug(0) << "Made request. Making callback.." << std::endl;
+ // pp::CompletionCallback callback = factory->NewCallback(&Manager::OnOpen);
+ pp::CompletionCallback callback(&Manager::doStartOpen, this);
+ Global::debug(0) << "Made callback" << std::endl;
+ core->CallOnMainThread(0, callback, 0);
+ // request->start(callback, core);
/* the handler will call into the browser. the browser will asynchounsly
* call the handler again and the handler will call run2 to finish up
*/
Global::debug(0) << "Releasing control back to the browser" << std::endl;
}
- static int run(void * me){
- Manager * self = (Manager*) me;
- self->doit();
- return 0;
- }
-
void run2(){
portal.acquire();
Global::debug(0) << "File operation done" << std::endl;
operation.complete = true;
portal.signal();
+ delete factory;
+ factory = NULL;
portal.release();
}
/*
pp::URLRequestInfo request;
pp::URLLoader loader;
*/
};
-NetworkSystem::NetworkSystem(const string & serverPath, pp::Instance * instance):
+NetworkSystem::NetworkSystem(const string & serverPath, pp::Instance * instance, pp::Core * core):
instance(instance),
serverPath(serverPath),
-manager(new Manager(instance, portal)){
+manager(new Manager(instance, core, portal)){
}
/* TODO */
NetworkSystem::~NetworkSystem(){
}
/* TODO */
AbsolutePath NetworkSystem::find(const RelativePath & path){
return Util::getDataPath2().join(path);
}
/* TODO */
RelativePath NetworkSystem::cleanse(const AbsolutePath & path){
return RelativePath();
}
bool NetworkSystem::exists(const RelativePath & path){
try{
AbsolutePath absolute = find(path);
return true;
} catch (const Storage::NotFound & found){
return false;
}
}
/*
class Handler{
public:
Handler(pp::Instance * instance, const AbsolutePath & path, NetworkSystem * system):
request(instance),
loader(instance),
factory(this),
http(false),
system(system){
request.SetURL(path.path());
request.SetMethod("GET");
}
virtual void start(){
pp::CompletionCallback callback = factory.NewCallback(&Handler::OnOpen);
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Open " << ok << std::endl;
if (ok != PP_OK_COMPLETIONPENDING){
callback.Run(ok);
}
Global::debug(0) << "Callback running" << std::endl;
}
virtual void OnOpen(int32_t ok){
Global::debug(0) << "Opened! " << ok << std::endl;
system->run2();
}
pp::URLRequestInfo request;
pp::URLLoader loader;
pp::CompletionCallbackFactory<Handler> factory;
volatile bool http;
NetworkSystem * system;
};
*/
void NetworkSystem::run(){
+ manager->run();
+ /*
Util::Thread::Id thread;
Util::Thread::createThread(&thread, NULL, &Manager::run, manager);
+ */
// manager->run();
}
bool NetworkSystem::exists(const AbsolutePath & path){
/*
Global::debug(0) << "Checking for " << path.path() << std::endl;
pp::CompletionCallback::Block blocking;
pp::CompletionCallback callback(blocking);
pp::URLRequestInfo request(instance);
pp::URLLoader loader(instance);
string url = serverPath + path.path();
Global::debug(0) << "Url: " << url << std::endl;
// request.SetURL(serverPath + path.path());
request.SetURL("/" + path.path());
request.SetMethod("GT");
int32_t ok = loader.Open(request, callback);
Global::debug(0) << "Ok: " << ok << std::endl;
if (ok == PP_OK){
return true;
} else {
return false;
}
*/
- portal.acquire();
+ Global::debug(0) << "Getting portal lock" << std::endl;
+ if (portal.acquire() != 0){
+ Global::debug(0) << "Lock failed!" << std::endl;
+ }
+ /*
+ Global::debug(0) << "Getting portal lock again" << std::endl;
+ if (portal.acquire() != 0){
+ Global::debug(0) << "Lock failed again!" << std::endl;
+ }
+ Global::debug(0) << "Somehow got the portal lock twice??" << std::endl;
+ */
operation.type = Exists;
operation.absolute = path;
operation.complete = false;
operation.success = false;
Global::debug(0) << "Request open" << std::endl;
run();
// portal.signal();
+ Global::debug(0) << "Waiting on portal" << std::endl;
portal.wait(operation.complete);
portal.release();
Global::debug(0) << "Request open complete" << std::endl;
- return false;
+ return operation.success;
/*
Handler handler(instance, path);
handler.start();
handler.wait();
return false;
*/
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
std::vector<AbsolutePath> paths;
return paths;
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive){
std::vector<AbsolutePath> paths;
return paths;
}
/* TODO */
AbsolutePath NetworkSystem::configFile(){
return AbsolutePath();
}
/* TODO */
AbsolutePath NetworkSystem::userDirectory(){
return AbsolutePath();
}
/* TODO */
std::vector<AbsolutePath> NetworkSystem::findDirectories(const RelativePath & path){
return std::vector<AbsolutePath>();
}
/* TODO */
AbsolutePath NetworkSystem::findInsensitive(const RelativePath & path){
return AbsolutePath();
}
/* TODO */
AbsolutePath NetworkSystem::lookupInsensitive(const AbsolutePath & directory, const RelativePath & path){
return AbsolutePath();
}
}
#endif
diff --git a/util/nacl/network-system.h b/util/nacl/network-system.h
index 39375f24..c6b1baf0 100644
--- a/util/nacl/network-system.h
+++ b/util/nacl/network-system.h
@@ -1,50 +1,52 @@
#ifndef _paintown_network_system_h
#define _paintown_network_system_h
#ifdef NACL
#include <string>
#include "../file-system.h"
#include "../thread.h"
namespace pp{
class Instance;
+ class Core;
}
namespace Nacl{
typedef Path::AbsolutePath AbsolutePath;
typedef Path::RelativePath RelativePath;
class Manager;
class NetworkSystem: public Storage::System {
public:
- NetworkSystem(const std::string & serverPath, pp::Instance * instance);
+ NetworkSystem(const std::string & serverPath, pp::Instance * instance, pp::Core * core);
virtual ~NetworkSystem();
virtual AbsolutePath find(const RelativePath & path);
virtual RelativePath cleanse(const AbsolutePath & path);
virtual bool exists(const RelativePath & path);
virtual bool exists(const AbsolutePath & path);
virtual std::vector<AbsolutePath> getFilesRecursive(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
virtual std::vector<AbsolutePath> getFiles(const AbsolutePath & dataPath, const std::string & find, bool caseInsensitive = false);
virtual AbsolutePath configFile();
virtual AbsolutePath userDirectory();
virtual std::vector<AbsolutePath> findDirectories(const RelativePath & path);
virtual AbsolutePath findInsensitive(const RelativePath & path);
virtual AbsolutePath lookupInsensitive(const AbsolutePath & directory, const RelativePath & path);
virtual void run();
protected:
pp::Instance * instance;
+ pp::Core * core;
std::string serverPath;
Util::Thread::LockObject portal;
Manager * manager;
};
}
#endif
#endif
diff --git a/util/thread.cpp b/util/thread.cpp
index c0bf8a2c..018b1c10 100644
--- a/util/thread.cpp
+++ b/util/thread.cpp
@@ -1,354 +1,362 @@
#include "thread.h"
namespace Util{
namespace Thread{
LockObject::LockObject(){
initializeLock(&lock);
initializeCondition(&condition);
+ // Global::debug(0) << "Created lock " << lock << std::endl;
+ // Global::debug(0) << "Created condition " << condition << std::endl;
}
-void LockObject::acquire() const {
+int LockObject::acquire() const {
/* quick hack to get around annoying constness */
- acquireLock((Lock*) &lock);
+ return acquireLock((Lock*) &lock);
}
-void LockObject::release() const {
- releaseLock((Lock*) &lock);
+int LockObject::release() const {
+ return releaseLock((Lock*) &lock);
}
void LockObject::wait() const {
int ok = 1;
while (ok != 0){
/* if conditionWait succeeds then ok will be 0 */
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::wait(volatile bool & check) const {
int ok = 0;
/* only wait if check is false. if so then keep waiting until the condition
* was successful as well.
*/
while (!check || ok != 0){
+ if (ok != 0){
+ // Global::debug(0) << "Wait failed: " << SDL_GetError() << std::endl;
+ }
ok = conditionWait((Condition*) &condition, (Lock*) &lock);
}
}
void LockObject::signal() const {
conditionSignal((Condition*) &condition);
}
void LockObject::lockAndSignal(volatile bool & check, bool what) const {
acquire();
check = what;
signal();
release();
}
LockObject::~LockObject(){
destroyLock(&lock);
destroyCondition(&condition);
}
ScopedLock::ScopedLock(const LockObject & lock):
lock(lock){
lock.acquire();
}
ScopedLock::~ScopedLock(){
lock.release();
}
bool isUninitialized(Id thread){
return thread == uninitializedValue;
}
-#ifdef USE_SDL
+#if defined(USE_SDL) && !defined(USE_NACL)
Id uninitializedValue = NULL;
void initializeLock(Lock * lock){
*lock = SDL_CreateMutex();
}
int acquireLock(Lock * lock){
return SDL_LockMutex(*lock);
}
int releaseLock(Lock * lock){
return SDL_UnlockMutex(*lock);
}
void destroyLock(Lock * lock){
SDL_DestroyMutex(*lock);
}
void initializeCondition(Condition * condition){
*condition = SDL_CreateCond();
+ if (condition == NULL){
+ Global::debug(0) << "Could not create condition" << std::endl;
+ }
}
void destroyCondition(Condition * condition){
SDL_DestroyCond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
return SDL_CondWait(*condition, *lock);
}
int conditionSignal(Condition * condition){
return SDL_CondBroadcast(*condition);
}
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
*semaphore = SDL_CreateSemaphore(value);
}
void destroySemaphore(Semaphore * semaphore){
SDL_DestroySemaphore(*semaphore);
}
void semaphoreDecrease(Semaphore * semaphore){
SDL_SemWait(*semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
SDL_SemPost(*semaphore);
}
*/
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
*thread = SDL_CreateThread(function, arg);
return *thread != NULL;
}
void joinThread(Id thread){
SDL_WaitThread(thread, NULL);
}
void cancelThread(Id thread){
#ifndef PS3
SDL_KillThread(thread);
#endif
}
#elif USE_ALLEGRO5
Id uninitializedValue = 0;
void initializeLock(Lock * lock){
*lock = al_create_mutex();
}
int acquireLock(Lock * lock){
al_lock_mutex(*lock);
return 0;
}
int releaseLock(Lock * lock){
al_unlock_mutex(*lock);
return 0;
}
void initializeCondition(Condition * condition){
*condition = al_create_cond();
}
void destroyCondition(Condition * condition){
al_destroy_cond(*condition);
}
int conditionWait(Condition * condition, Lock * lock){
al_wait_cond(*condition, *lock);
return 0;
}
int conditionSignal(Condition * condition){
al_broadcast_cond(*condition);
return 0;
}
struct AllegroThreadStuff{
AllegroThreadStuff(const ThreadFunction & function, void * arg):
function(function),
arg(arg){
}
ThreadFunction function;
void * arg;
};
static void * allegro_start_thread(ALLEGRO_THREAD * self, void * _stuff){
AllegroThreadStuff * stuff = (AllegroThreadStuff*) _stuff;
ThreadFunction function = stuff->function;
void * arg = stuff->arg;
delete stuff;
return function(arg);
}
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
AllegroThreadStuff * stuff = new AllegroThreadStuff(function, arg);
*thread = al_create_thread(allegro_start_thread, stuff);
if (*thread != NULL){
al_start_thread(*thread);
return true;
} else {
delete stuff;
return false;
}
}
void joinThread(Id thread){
al_join_thread(thread, NULL);
}
void cancelThread(Id thread){
al_destroy_thread(thread);
}
void destroyLock(Lock * lock){
al_destroy_mutex(*lock);
}
#else
Id uninitializedValue = 0;
void initializeLock(Lock * lock){
pthread_mutex_init(lock, NULL);
}
int acquireLock(Lock * lock){
return pthread_mutex_lock(lock);
}
int releaseLock(Lock * lock){
return pthread_mutex_unlock(lock);
}
void initializeCondition(Condition * condition){
pthread_cond_init(condition, NULL);
}
void destroyCondition(Condition * condition){
pthread_cond_destroy(condition);
}
int conditionWait(Condition * condition, Lock * lock){
return pthread_cond_wait(condition, lock);
}
int conditionSignal(Condition * condition){
return pthread_cond_broadcast(condition);
}
#if 0
void initializeSemaphore(Semaphore * semaphore, unsigned int value){
sem_init(semaphore, 0, value);
}
void destroySemaphore(Semaphore * semaphore){
/* nothing */
}
void semaphoreDecrease(Semaphore * semaphore){
sem_wait(semaphore);
}
void semaphoreIncrease(Semaphore * semaphore){
sem_post(semaphore);
}
#endif
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg){
return pthread_create(thread, (pthread_attr_t*) attributes, function, arg) == 0;
}
void joinThread(Id thread){
pthread_join(thread, NULL);
}
void cancelThread(Id thread){
/* FIXME: cancel is not implemented for libogc, find another way.
* thread suspend/resume is there, though.
*/
-#if !defined(WII)
+#if !defined(WII) && !defined(USE_NACL)
pthread_cancel(thread);
#endif
}
void destroyLock(Lock * lock){
/* nothing */
}
#endif
}
WaitThread::WaitThread():
done(false){
Thread::initializeLock(&doneLock);
}
WaitThread::WaitThread(Thread::ThreadFunction thread, void * arg){
Thread::initializeLock(&doneLock);
start(thread, arg);
}
static void * do_thread(void * arg){
WaitThread * thread = (WaitThread *) arg;
thread->doRun();
return NULL;
}
void WaitThread::doRun(){
this->function(this->arg);
Thread::acquireLock(&doneLock);
this->done = true;
Thread::releaseLock(&doneLock);
}
void WaitThread::start(Thread::ThreadFunction thread, void * arg){
done = false;
this->arg = arg;
this->function = thread;
Thread::createThread(&this->thread, NULL, (Thread::ThreadFunction) do_thread, this);
}
bool WaitThread::isRunning(){
Thread::acquireLock(&doneLock);
bool what = done;
Thread::releaseLock(&doneLock);
return what;
}
void WaitThread::kill(){
Thread::cancelThread(thread);
Thread::joinThread(thread);
}
WaitThread::~WaitThread(){
/* FIXME: Should we join the thread? */
/* pthread_join(thread); */
Thread::joinThread(thread);
}
ThreadBoolean::ThreadBoolean(volatile bool & what, Thread::Lock & lock):
what(what),
lock(lock){
}
bool ThreadBoolean::get(){
Thread::acquireLock(&lock);
bool b = what;
Thread::releaseLock(&lock);
return b;
}
void ThreadBoolean::set(bool value){
Thread::acquireLock(&lock);
what = value;
Thread::releaseLock(&lock);
}
}
diff --git a/util/thread.h b/util/thread.h
index 37171480..74a45182 100644
--- a/util/thread.h
+++ b/util/thread.h
@@ -1,268 +1,272 @@
#ifndef _paintown_thread_h
#define _paintown_thread_h
-#ifdef USE_SDL
+/* FIXME: NACL should be able to use SDL threads but they are broken
+ * for some reason. SDL is implemented in terms of pthreads anyway
+ * so for now just use the native pthreads implementation.
+ */
+#if defined(USE_SDL) && !defined(USE_NACL)
#include <SDL_thread.h>
#include <SDL_mutex.h>
#elif USE_ALLEGRO5
#include <allegro5/allegro5.h>
#else
#include <pthread.h>
// #include <semaphore.h>
#endif
#include "exceptions/exception.h"
#include "load_exception.h"
#include "token_exception.h"
#include "mugen/exception.h"
// #include "funcs.h"
#include "debug.h"
namespace Util{
/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
typedef SDL_mutex* Lock;
typedef SDL_Thread* Id;
typedef int (*ThreadFunction)(void*);
typedef SDL_cond* Condition;
// typedef SDL_semaphore* Semaphore;
#elif USE_ALLEGRO5
typedef ALLEGRO_MUTEX* Lock;
typedef ALLEGRO_THREAD* Id;
typedef void * (*ThreadFunction)(void*);
typedef ALLEGRO_COND* Condition;
// typedef SDL_semaphore* Semaphore;
#else
typedef pthread_mutex_t Lock;
typedef pthread_t Id;
typedef pthread_cond_t Condition;
// typedef sem_t Semaphore;
typedef void * (*ThreadFunction)(void*);
#endif
extern Id uninitializedValue;
bool isUninitialized(Id thread);
void initializeLock(Lock * lock);
void initializeCondition(Condition * condition);
void destroyCondition(Condition * condition);
int conditionWait(Condition * condition, Lock * lock);
int conditionSignal(Condition * condition);
/*
void initializeSemaphore(Semaphore * semaphore, unsigned int value);
void destroySemaphore(Semaphore * semaphore);
void semaphoreDecrease(Semaphore * semaphore);
void semaphoreIncrease(Semaphore * semaphore);
*/
int acquireLock(Lock * lock);
int releaseLock(Lock * lock);
void destroyLock(Lock * lock);
bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
void joinThread(Id thread);
void cancelThread(Id thread);
/* wraps a Lock in a c++ class */
class LockObject{
public:
LockObject();
- void acquire() const;
- void release() const;
+ int acquire() const;
+ int release() const;
/* wait until check is true.
* you MUST acquire the lock before calling this function */
void wait(volatile bool & check) const;
/* just until we are signaled
* you MUST acquire the lock before calling this function */
void wait() const;
/* you MUST acquire the lock before calling this function */
void signal() const;
/* gets the lock, sets the boolean, and signals the condition
* you MUST NOT acquire the lock before calling this function
*/
void lockAndSignal(volatile bool & check, bool what) const;
virtual ~LockObject();
Lock lock;
Condition condition;
};
/* acquires/releases the lock in RAII fashion */
class ScopedLock{
public:
ScopedLock(const LockObject & lock);
~ScopedLock();
private:
const LockObject & lock;
};
}
class WaitThread{
public:
/* does not start a new thread yet */
WaitThread();
/* starts a thread */
WaitThread(Thread::ThreadFunction thread, void * arg);
/* starts a thread */
void start(Thread::ThreadFunction thread, void * arg);
bool isRunning();
void kill();
virtual ~WaitThread();
public:
/* actually runs the thread */
void doRun();
protected:
Thread::Lock doneLock;
Thread::Id thread;
volatile bool done;
void * arg;
Thread::ThreadFunction function;
};
/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
ThreadBoolean(volatile bool & what, Thread::Lock & lock);
bool get();
void set(bool value);
protected:
volatile bool & what;
Thread::Lock & lock;
};
/* Computes stuff in a separate thread and gives it back when you ask for it.
* As soon as the future is created a thread will start executing and compute
* whatever it is that the class is supposed to do. You can then call `get'
* on the future object to get the result. If the thread is still executing
* then `get' will block until the future completes. If the future has already
* completed then `get' will return immediately with the computed value.
* The use case is computing something that has to be used later:
* Future future; // might take a while to compute
* do_stuff_that_takes_a_while(); // future might finish sometime in here
* Object o = future.get(); // future is already done
*
* TODO: handle exceptions
*/
template<class X>
class Future{
protected:
/* WARNING: hack to find out the type of the exception */
/*
enum ExceptionType{
None,
Load,
Token,
Base,
Mugen
};
*/
public:
Future():
thing(0),
thread(Thread::uninitializedValue),
done(false),
exception(NULL){
/* future will increase the count */
// Thread::initializeSemaphore(&future, 0);
// future.acquire();
}
virtual ~Future(){
if (Thread::isUninitialized(thread)){
Thread::joinThread(thread);
}
// Thread::destroySemaphore(&future);
delete exception;
}
virtual X get(){
X out;
Exception::Base * failed = NULL;
future.acquire();
future.wait(done);
// Thread::semaphoreDecrease(&future);
if (exception != NULL){
failed = exception;
// exception->throwSelf();
}
out = thing;
// Thread::semaphoreIncrease(&future);
future.release();
if (failed){
failed->throwSelf();
}
return out;
}
virtual void start(){
if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
Global::debug(0) << "Could not create future thread. Blocking until its done" << std::endl;
runit(this);
// throw Exception::Base(__FILE__, __LINE__);
}
}
protected:
bool isDone(){
Thread::ScopedLock scoped(future);
return done;
}
static void * runit(void * arg){
Future<X> * me = (Future<X>*) arg;
try{
me->compute();
} catch (const LoadException & load){
me->exception = new LoadException(load);
} catch (const TokenException & t){
me->exception = new TokenException(t);
} catch (const MugenException & m){
me->exception = new MugenException(m);
} catch (const Exception::Base & base){
me->exception = new Exception::Base(base);
}
me->future.lockAndSignal(me->done, true);
/*
me->future.acquire();
me->done = true;
me->future.signal();
me->future.release();
*/
// Thread::semaphoreIncrease(&me->future);
return NULL;
}
virtual void set(X x){
this->thing = x;
}
virtual void compute() = 0;
X thing;
Thread::Id thread;
Thread::LockObject future;
volatile bool done;
/* if any exceptions occur, throw them from `get' */
Exception::Base * exception;
};
}
#endif

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jun 11, 10:26 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68400
Default Alt Text
(32 KB)

Event Timeline