Initial source commit
This commit is contained in:
commit
f1384c11ee
335 changed files with 52715 additions and 0 deletions
192
minorGems/system/linux/BinarySemaphoreLinux.cpp
Normal file
192
minorGems/system/linux/BinarySemaphoreLinux.cpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Modification History
|
||||
*
|
||||
* 2001-January-11 Jason Rohrer
|
||||
* Created.
|
||||
*
|
||||
* 2003-August-26 Jason Rohrer
|
||||
* Added support for timeouts on wait.
|
||||
*
|
||||
* 2006-February-28 Jason Rohrer
|
||||
* Fixed bug in sub-second timeout computation.
|
||||
*/
|
||||
|
||||
#include "minorGems/system/BinarySemaphore.h"
|
||||
#include "minorGems/system/Time.h"
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
/**
|
||||
* Linux-specific implementation of the BinarySemaphore class member functions.
|
||||
*
|
||||
* May also be compatible with other POSIX-like systems.
|
||||
*
|
||||
* To compile:
|
||||
* g++ -lpthread
|
||||
*/
|
||||
|
||||
/**
|
||||
* Native object pointer A is the condition variable.
|
||||
* Pointer B is the mutex that must go along with it.
|
||||
*/
|
||||
|
||||
|
||||
BinarySemaphore::BinarySemaphore() :
|
||||
mSemaphoreValue( 0 ) {
|
||||
|
||||
// allocate a condition variable structure on the heap
|
||||
mNativeObjectPointerA = (void *)( new pthread_cond_t[1] );
|
||||
|
||||
// get a pointer to the cond
|
||||
pthread_cond_t *condPointer =
|
||||
(pthread_cond_t *)mNativeObjectPointerA;
|
||||
|
||||
// init the cond
|
||||
pthread_cond_init( &( condPointer[0] ), NULL );
|
||||
|
||||
|
||||
// allocate a mutex structure on the heap
|
||||
mNativeObjectPointerB = (void *)( new pthread_mutex_t[1] );
|
||||
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointerB;
|
||||
|
||||
// init the mutex
|
||||
pthread_mutex_init( &( mutexPointer[0] ), NULL );
|
||||
|
||||
}
|
||||
|
||||
BinarySemaphore::~BinarySemaphore() {
|
||||
|
||||
// get a pointer to the cond
|
||||
pthread_cond_t *condPointer =
|
||||
(pthread_cond_t *)mNativeObjectPointerA;
|
||||
|
||||
// destroy the cond
|
||||
pthread_cond_destroy( &( condPointer[0] ) );
|
||||
|
||||
// de-allocate the cond structure from the heap
|
||||
delete [] condPointer;
|
||||
|
||||
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointerB;
|
||||
|
||||
// destroy the mutex
|
||||
pthread_mutex_destroy( &( mutexPointer[0] ) );
|
||||
|
||||
// de-allocate the mutex structure from the heap
|
||||
delete [] mutexPointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BinarySemaphore::wait( int inTimeoutInMilliseconds ) {
|
||||
|
||||
int returnValue = 1;
|
||||
|
||||
// get a pointer to the cond
|
||||
pthread_cond_t *condPointer =
|
||||
(pthread_cond_t *)mNativeObjectPointerA;
|
||||
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointerB;
|
||||
|
||||
|
||||
// lock the mutex
|
||||
pthread_mutex_lock( &( mutexPointer[0] ) );
|
||||
|
||||
if( mSemaphoreValue == 0 ) {
|
||||
// wait on condition variable, which automatically unlocks
|
||||
// the passed-in mutex
|
||||
|
||||
if( inTimeoutInMilliseconds == -1 ) {
|
||||
// no timeout
|
||||
pthread_cond_wait( &( condPointer[0] ), &( mutexPointer[0] ) );
|
||||
}
|
||||
else {
|
||||
// use timeout version
|
||||
|
||||
unsigned long nsecPerSecond = 1000000000;
|
||||
unsigned long nsecPerMillisecond = 1000000;
|
||||
|
||||
|
||||
unsigned long currentSec;
|
||||
unsigned long currentMS;
|
||||
|
||||
Time::getCurrentTime( ¤tSec, ¤tMS );
|
||||
|
||||
unsigned long currentNS = currentMS * nsecPerMillisecond;
|
||||
|
||||
|
||||
long timeoutSec = inTimeoutInMilliseconds / 1000;
|
||||
long extraMS = inTimeoutInMilliseconds % 1000;
|
||||
|
||||
long extraNS = extraMS * nsecPerMillisecond;
|
||||
|
||||
|
||||
|
||||
unsigned long absTimeoutSec = currentSec + timeoutSec;
|
||||
unsigned long absTimeoutNsec = currentNS + extraNS;
|
||||
|
||||
// check for nsec overflow
|
||||
if( absTimeoutNsec > nsecPerSecond ) {
|
||||
absTimeoutSec += 1;
|
||||
absTimeoutNsec -= nsecPerSecond;
|
||||
}
|
||||
|
||||
struct timespec abstime;
|
||||
abstime.tv_sec = absTimeoutSec;
|
||||
abstime.tv_nsec = absTimeoutNsec;
|
||||
|
||||
int result = pthread_cond_timedwait( &( condPointer[0] ),
|
||||
&( mutexPointer[0] ),
|
||||
&abstime );
|
||||
|
||||
if( result != 0 ) {
|
||||
// timed out
|
||||
returnValue = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// mutex is apparently re-locked when we return from cond_wait
|
||||
|
||||
}
|
||||
|
||||
// decrement the semaphore value
|
||||
mSemaphoreValue = 0;
|
||||
|
||||
// unlock the mutex again
|
||||
pthread_mutex_unlock( &( mutexPointer[0] ) );
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BinarySemaphore::signal() {
|
||||
|
||||
// get a pointer to the cond
|
||||
pthread_cond_t *condPointer =
|
||||
(pthread_cond_t *)mNativeObjectPointerA;
|
||||
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointerB;
|
||||
|
||||
|
||||
// lock the mutex
|
||||
pthread_mutex_lock( &( mutexPointer[0] ) );
|
||||
|
||||
// increment the semaphore value
|
||||
mSemaphoreValue = 1;
|
||||
|
||||
pthread_cond_signal( &( condPointer[0] ) );
|
||||
|
||||
|
||||
// unlock the mutex
|
||||
pthread_mutex_unlock( &( mutexPointer[0] ) );
|
||||
}
|
76
minorGems/system/linux/MutexLockLinux.cpp
Normal file
76
minorGems/system/linux/MutexLockLinux.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Modification History
|
||||
*
|
||||
* 2000-December-13 Jason Rohrer
|
||||
* Created.
|
||||
*
|
||||
* 2002-October-18 Jason Rohrer
|
||||
* Moved common include out of header and into platform-specific cpp files,
|
||||
* since MemoryTrack uses a mutex lock.
|
||||
* Changed to use malloc instead of new internally to work with debugMemory.
|
||||
* Made use of mNativeObjectPointer a bit cleaner.
|
||||
*/
|
||||
|
||||
#include "minorGems/common.h"
|
||||
|
||||
|
||||
|
||||
#include <minorGems/system/MutexLock.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* Linux-specific implementation of the MutexLock class member functions.
|
||||
*
|
||||
* May also be compatible with other POSIX-like systems.
|
||||
*
|
||||
* To compile:
|
||||
* g++ -lpthread
|
||||
*/
|
||||
|
||||
|
||||
MutexLock::MutexLock() {
|
||||
// allocate a mutex structure on the heap
|
||||
mNativeObjectPointer = malloc( sizeof( pthread_mutex_t ) );
|
||||
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointer;
|
||||
|
||||
// init the mutex
|
||||
pthread_mutex_init( mutexPointer, NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
MutexLock::~MutexLock() {
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointer;
|
||||
|
||||
// destroy the mutex
|
||||
pthread_mutex_destroy( mutexPointer );
|
||||
|
||||
// de-allocate the mutex structure from the heap
|
||||
free( mNativeObjectPointer );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MutexLock::lock() {
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointer;
|
||||
|
||||
pthread_mutex_lock( mutexPointer );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MutexLock::unlock() {
|
||||
// get a pointer to the mutex
|
||||
pthread_mutex_t *mutexPointer =
|
||||
(pthread_mutex_t *)mNativeObjectPointer;
|
||||
|
||||
pthread_mutex_unlock( mutexPointer );
|
||||
}
|
247
minorGems/system/linux/ThreadLinux.cpp
Normal file
247
minorGems/system/linux/ThreadLinux.cpp
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* Modification History
|
||||
*
|
||||
* 2000-December-13 Jason Rohrer
|
||||
* Created.
|
||||
*
|
||||
* 2001-January-11 Jason Rohrer
|
||||
* Added missing sleep() implementation.
|
||||
*
|
||||
* 2002-March-27 Jason Rohrer
|
||||
* Added support for gprof-friendly thread wrappers.
|
||||
* Fixed a compile bug when gprof threads disabled.
|
||||
*
|
||||
* 2002-August-5 Jason Rohrer
|
||||
* Removed an unused variable.
|
||||
*
|
||||
* 2003-February-3 Jason Rohrer
|
||||
* Fixed sleep to be thread safe (signals were interrupting thread sleeps).
|
||||
*
|
||||
* 2004-March-31 Jason Rohrer
|
||||
* Added support for detatched mode.
|
||||
*
|
||||
* 2005-January-22 Jason Rohrer
|
||||
* Added a static sleep function.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <minorGems/system/Thread.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Linux-specific implementation of the Thread class member functions.
|
||||
*
|
||||
* May also be compatible with other POSIX-like systems.
|
||||
*
|
||||
* To compile:
|
||||
* g++ -lpthread
|
||||
* If thread profiling is desired for gprof on linux, compile
|
||||
* with -DUSE_GPROF_THREADS (otherwise, only main thread is profiled).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef USE_GPROF_THREADS
|
||||
// prototype
|
||||
int gprof_pthread_create( pthread_t * thread, pthread_attr_t * attr,
|
||||
void * (*start_routine)(void *), void * arg );
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// prototype
|
||||
/**
|
||||
* A wrapper for the run method, since pthreads won't take
|
||||
* a class's member function. Takes a pointer to the Thread to run,
|
||||
* cast as a void*;
|
||||
*/
|
||||
void *linuxThreadFunction( void * );
|
||||
|
||||
|
||||
|
||||
Thread::Thread() {
|
||||
// allocate a pthread structure on the heap
|
||||
mNativeObjectPointer = (void *)( new pthread_t[1] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Thread::~Thread() {
|
||||
// de-allocate the pthread structure from the heap
|
||||
pthread_t *threadPointer = (pthread_t *)mNativeObjectPointer;
|
||||
delete [] threadPointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Thread::start( char inDetach ) {
|
||||
|
||||
mIsDetached = inDetach;
|
||||
|
||||
// get a pointer to the pthread
|
||||
pthread_t *threadPointer = (pthread_t *)mNativeObjectPointer;
|
||||
|
||||
// create the pthread, which also sets it running
|
||||
#ifdef USE_GPROF_THREADS
|
||||
gprof_pthread_create( &( threadPointer[0] ), NULL,
|
||||
linuxThreadFunction, (void*)this );
|
||||
#else
|
||||
pthread_create( &( threadPointer[0] ), NULL,
|
||||
linuxThreadFunction, (void*)this );
|
||||
#endif
|
||||
|
||||
if( mIsDetached ) {
|
||||
pthread_detach( threadPointer[0] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Thread::join() {
|
||||
void *joinStat;
|
||||
|
||||
pthread_t *threadPointer = (pthread_t *)mNativeObjectPointer;
|
||||
|
||||
pthread_join( threadPointer[0], &joinStat );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Thread::staticSleep( unsigned long inTimeInMilliseconds ) {
|
||||
|
||||
unsigned long seconds = inTimeInMilliseconds / 1000;
|
||||
unsigned long milliseconds = inTimeInMilliseconds % 1000;
|
||||
|
||||
struct timespec remainingSleepTimeStruct;
|
||||
remainingSleepTimeStruct.tv_sec = seconds;
|
||||
remainingSleepTimeStruct.tv_nsec = milliseconds * 1000000;
|
||||
|
||||
struct timespec timeToSleepStruct;
|
||||
|
||||
// sleep repeatedly, ignoring signals, untill we use up all of the time
|
||||
int sleepReturn = -1;
|
||||
while( sleepReturn == -1 ) {
|
||||
|
||||
timeToSleepStruct.tv_sec = remainingSleepTimeStruct.tv_sec;
|
||||
timeToSleepStruct.tv_nsec = remainingSleepTimeStruct.tv_nsec;
|
||||
|
||||
sleepReturn =
|
||||
nanosleep( &timeToSleepStruct, &remainingSleepTimeStruct );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// takes a pointer to a Thread object as the data value
|
||||
void *linuxThreadFunction( void *inPtrToThread ) {
|
||||
Thread *threadToRun = (Thread *)inPtrToThread;
|
||||
threadToRun->run();
|
||||
|
||||
if( threadToRun->isDetatched() ) {
|
||||
// thread detached, so we must destroy it
|
||||
delete threadToRun;
|
||||
}
|
||||
|
||||
return inPtrToThread;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef USE_GPROF_THREADS
|
||||
|
||||
|
||||
|
||||
// found at http://sam.zoy.org/doc/programming/gprof.html
|
||||
#include <sys/time.h>
|
||||
/*
|
||||
* pthread_create wrapper for gprof compatibility
|
||||
*
|
||||
* needed headers: <pthread.h>
|
||||
* <sys/time.h>
|
||||
*/
|
||||
typedef struct wrapper_s {
|
||||
void * (*start_routine)(void *);
|
||||
void * arg;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t wait;
|
||||
struct itimerval itimer;
|
||||
} wrapper_t;
|
||||
|
||||
|
||||
|
||||
static void * wrapper_routine(void *);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Same prototype as pthread_create; use some #define magic to
|
||||
* transparently replace it in other files
|
||||
*/
|
||||
int gprof_pthread_create( pthread_t * thread, pthread_attr_t * attr,
|
||||
void * (*start_routine)(void *), void * arg ) {
|
||||
|
||||
wrapper_t wrapper_data;
|
||||
int i_return;
|
||||
|
||||
/* Initialize the wrapper structure */
|
||||
wrapper_data.start_routine = start_routine;
|
||||
wrapper_data.arg = arg;
|
||||
getitimer(ITIMER_PROF, &wrapper_data.itimer);
|
||||
pthread_cond_init(&wrapper_data.wait, NULL);
|
||||
pthread_mutex_init(&wrapper_data.lock, NULL);
|
||||
pthread_mutex_lock(&wrapper_data.lock);
|
||||
|
||||
/* The real pthread_create call */
|
||||
i_return = pthread_create(thread, attr, &wrapper_routine,
|
||||
&wrapper_data);
|
||||
|
||||
/* If the thread was successfully spawned, wait for the data
|
||||
* to be released */
|
||||
if( i_return == 0 ) {
|
||||
pthread_cond_wait(&wrapper_data.wait, &wrapper_data.lock);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&wrapper_data.lock);
|
||||
pthread_mutex_destroy(&wrapper_data.lock);
|
||||
pthread_cond_destroy(&wrapper_data.wait);
|
||||
return i_return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The wrapper function in charge for setting the itimer value
|
||||
*/
|
||||
static void * wrapper_routine( void * data ) {
|
||||
|
||||
/* Put user data in thread-local variables */
|
||||
void * (*start_routine)(void *) = ((wrapper_t*)data)->start_routine;
|
||||
void * arg = ((wrapper_t*)data)->arg;
|
||||
|
||||
/* Set the profile timer value */
|
||||
setitimer(ITIMER_PROF, &((wrapper_t*)data)->itimer, NULL);
|
||||
|
||||
/* Tell the calling thread that we don't need its data anymore */
|
||||
pthread_mutex_lock(&((wrapper_t*)data)->lock);
|
||||
pthread_cond_signal(&((wrapper_t*)data)->wait);
|
||||
pthread_mutex_unlock(&((wrapper_t*)data)->lock);
|
||||
|
||||
/* Call the real function */
|
||||
return start_routine(arg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue