Initial source commit

This commit is contained in:
Tony Bark 2025-10-03 02:19:59 -04:00
commit f1384c11ee
335 changed files with 52715 additions and 0 deletions

View 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( &currentSec, &currentMS );
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] ) );
}

View 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 );
}

View 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