Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F629534
thread.h
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
thread.h
View Options
#ifndef _paintown_thread_h
#define _paintown_thread_h
/* 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.h>
#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 "exceptions/load_exception.h"
#include "token_exception.h"
#include "mugen/exception.h"
*/
// #include "funcs.h"
#include
"debug.h"
/* 9/10/2012: Condition variables have been removed. There are no use-cases in the code
* where multiple threads are waiting for producer thread to signal them so a simpler
* solution is just to use a mutex and poll. The main motivation to remove condition
* variables was in getting the xbox 360 port to work with libxenon which does not
* yet have support for condition variables, but supposedly mutexes work ok.
*/
namespace
Util
{
void
rest
(
int
x
);
/* 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
);
bool
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
();
int
acquire
()
const
;
int
release
()
const
;
Lock
&
getLock
(){
return
lock
;
}
/* 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
ThreadObject
{
public
:
ThreadObject
(
void
*
data
,
void
*
(
function
)(
void
*
arg
));
/* true if the thread was started, false otherwise */
virtual
bool
start
();
virtual
~
ThreadObject
();
protected
:
void
*
data
;
void
*
(
*
function
)(
void
*
arg
);
Id
thread
;
};
}
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.
* Call start() on the future to begin executing it. 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;
* future.start(); // 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
*
*/
template
<
class
X
>
class
Future
{
public
:
Future
()
:
thing
(
0
),
thread
(
Thread
::
uninitializedValue
),
done
(
false
),
exception
(
NULL
),
ran
(
false
){
}
virtual
~
Future
(){
Thread
::
joinThread
(
thread
);
delete
exception
;
}
virtual
X
get
(){
/* make sure the future has been started */
if
(
Thread
::
isUninitialized
(
thread
)){
start
();
}
Exception
::
Base
*
failed
=
NULL
;
bool
ok
=
false
;
while
(
!
ok
){
future
.
acquire
();
if
(
!
done
){
future
.
release
();
Util
::
rest
(
1
);
}
else
{
ok
=
true
;
}
}
if
(
exception
!=
NULL
){
failed
=
exception
;
}
X
out
=
thing
;
future
.
release
();
if
(
failed
){
failed
->
throwSelf
();
}
return
out
;
}
virtual
void
start
(){
if
(
ran
){
return
;
}
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
);
}
ran
=
true
;
}
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
=
base
.
copy
();
}
catch
(...){
me
->
exception
=
new
Exception
::
Base
(
__FILE__
,
__LINE__
);
}
me
->
future
.
acquire
();
me
->
done
=
true
;
me
->
future
.
release
();
// me->future.lockAndSignal(me->done, true);
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
;
/* if the future was already started this is true so it can't be
* accidentally started twice
*/
bool
ran
;
};
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Nov 15, 7:09 AM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
117473
Default Alt Text
thread.h (7 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline