Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F126028
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline