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,79 @@
/*
* Modification History
*
* 2001-January-11 Jason Rohrer
* Created.
*
* 2001-January-27 Jason Rohrer
* Fixed a bug in the precompiler directives.
*
* 2003-August-26 Jason Rohrer
* Added support for timeouts on wait.
*/
#include "minorGems/common.h"
#ifndef BINARY_SEMAPHORE_CLASS_INCLUDED
#define BINARY_SEMAPHORE_CLASS_INCLUDED
#include "MutexLock.h"
/**
* Binary semaphore class. Semaphore starts out with a value of 0.
*
* Note: Implementation for the functions defined here is provided
* separately for each platform (in the mac/ linux/ and win32/
* subdirectories).
*
* @author Jason Rohrer
*/
class BinarySemaphore {
public:
/**
* Constructs a binary semaphore.
*/
BinarySemaphore();
~BinarySemaphore();
/**
* Blocks on this semaphore until signal() is called by another thread.
* Note that if signal() has already been called before wait() is
* called, then this call will return immediately, though the semaphore
* is reset to 0 by this call.
*
* @param inTimeoutInMilliseconds the maximum time to wait in
* milliseconds, or -1 to wait forever. Defaults to -1.
*
* @return 1 if the semaphore was signaled, or 0 if it timed out.
*/
int wait( int inTimeoutInMilliseconds = -1 );
/**
* Signals the semaphore, allowing a waiting thread to return from
* its call to wait(). (The semaphore is set to 1 by this call if
* no thread is waiting on the semaphore currently.)
*/
void signal();
private:
// starts at 0
int mSemaphoreValue;
/**
* Used by platform-specific implementations.
*/
void *mNativeObjectPointerA;
void *mNativeObjectPointerB;
};
#endif

View file

@ -0,0 +1,59 @@
/*
* Modification History
*
* 2002-March-9 Jason Rohrer
* Created.
*
* 2002-March-11 Jason Rohrer
* Changed so that destructor joins thread.
*
* 2002-April-4 Jason Rohrer
* Changed name of lock to avoid confusion with subclass-provided locks.
*
* 2002-August-5 Jason Rohrer
* Fixed member initialization order to match declaration order.
*
* 2004-April-1 Jason Rohrer
* Moved from konspire2b into minorGems.
* Changed so that destructor does not join the thread.
*/
#include "FinishedSignalThread.h"
#include <stdio.h>
FinishedSignalThread::FinishedSignalThread()
: mFinishedLock( new MutexLock() ), mFinished( false ) {
}
FinishedSignalThread::~FinishedSignalThread() {
delete mFinishedLock;
}
char FinishedSignalThread::isFinished() {
mFinishedLock->lock();
char finished = mFinished;
mFinishedLock->unlock();
return finished;
}
void FinishedSignalThread::setFinished() {
mFinishedLock->lock();
mFinished = true;
mFinishedLock->unlock();
}

View file

@ -0,0 +1,100 @@
/*
* Modification History
*
* 2002-March-9 Jason Rohrer
* Created.
*
* 2002-March-10 Jason Rohrer
* Made destructor public.
*
* 2002-March-11 Jason Rohrer
* Changed so that destructor joins thread.
*
* 2002-April-4 Jason Rohrer
* Changed name of lock to avoid confusion with subclass-provided locks.
*
* 2004-April-1 Jason Rohrer
* Moved from konspire2b into minorGems.
* Changed so that destructor does not join the thread.
*
* 2004-November-19 Jason Rohrer
* Changed to virtual inheritance from Thread class.
*/
#ifndef FINISHED_SIGNAL_THREAD_INCLUDED
#define FINISHED_SIGNAL_THREAD_INCLUDED
#include "minorGems/system/Thread.h"
#include "minorGems/system/MutexLock.h"
/**
* Abstract subclass if thread that has a
* synchronized finished signal.
*
* @author Jason Rohrer
*/
class FinishedSignalThread : public virtual Thread {
public:
/**
* Only destroys this thread.
* Does not join.
*/
virtual ~FinishedSignalThread();
/**
* Gets whether this thread is finished and
* ready to be destroyed.
*
* @return true iff this thread is finished.
*/
char isFinished();
protected:
FinishedSignalThread();
/**
* Sets that this thread is finished and
* ready to be destroyed.
*
* For this class to work properly, the subclass
* MUST call this function at the end of its run method.
*/
void setFinished();
private:
MutexLock *mFinishedLock;
char mFinished;
};
#endif

View file

@ -0,0 +1,116 @@
/*
* Modification History
*
* 2004-November-9 Jason Rohrer
* Created.
* Modified from MUTE's ChannelReceivingThreadManager.
*
* 2005-January-9 Jason Rohrer
* Changed to sleep on a semaphore to allow sleep to be interrupted.
*/
#include "minorGems/system/FinishedSignalThreadManager.h"
FinishedSignalThreadManager::FinishedSignalThreadManager()
: mLock( new MutexLock() ),
mThreadVector( new SimpleVector<FinishedSignalThread *>() ),
mStopSignal( false ),
mSleepSemaphore( new BinarySemaphore() ) {
this->start();
}
FinishedSignalThreadManager::~FinishedSignalThreadManager() {
mLock->lock();
mStopSignal = true;
mLock->unlock();
// signal the sleeping semaphore to wake up the thread
mSleepSemaphore->signal();
this->join();
mLock->lock();
// destroy all remaining threads
int numThreads = mThreadVector->size();
for( int i=0; i<numThreads; i++ ) {
delete *( mThreadVector->getElement( i ) );
}
delete mThreadVector;
mLock->unlock();
delete mLock;
delete mSleepSemaphore;
}
void FinishedSignalThreadManager::addThread(
FinishedSignalThread *inThread ) {
mLock->lock();
mThreadVector->push_back( inThread );
mLock->unlock();
}
void FinishedSignalThreadManager::run() {
char stopped;
mLock->lock();
stopped = mStopSignal;
mLock->unlock();
while( !stopped ) {
// wait for 10 seconds
int wasSignaled = mSleepSemaphore->wait( 10000 );
if( wasSignaled == 1 ) {
// signaled... we should stop
return;
}
char foundFinished = true;
while( foundFinished ) {
foundFinished = false;
mLock->lock();
int numThreads = mThreadVector->size();
for( int i=0; i<numThreads && !foundFinished; i++ ) {
FinishedSignalThread *currentThread =
*( mThreadVector->getElement( i ) );
if( currentThread->isFinished() ) {
delete currentThread;
mThreadVector->deleteElement( i );
foundFinished = true;
}
}
mLock->unlock();
}
mLock->lock();
stopped = mStopSignal;
mLock->unlock();
}
}

View file

@ -0,0 +1,82 @@
/*
* Modification History
*
* 2004-November-9 Jason Rohrer
* Created.
* Modified from MUTE's ChannelReceivingThreadManager.
*
* 2005-January-9 Jason Rohrer
* Changed to sleep on a semaphore to allow sleep to be interrupted.
*/
#ifndef FINISHED_SIGNAL_THREAD_MANAGER_INCLUDED
#define FINISHED_SIGNAL_THREAD_MANAGER_INCLUDED
#include "minorGems/system/FinishedSignalThread.h"
#include "minorGems/util/SimpleVector.h"
#include "minorGems/system/Thread.h"
#include "minorGems/system/MutexLock.h"
#include "minorGems/system/BinarySemaphore.h"
/**
* A thread that manages the destruction of FinishedSignalThreads.
*
* @author Jason Rohrer.
*/
class FinishedSignalThreadManager : public Thread {
public:
/**
* Constructs and starts this manager.
*/
FinishedSignalThreadManager();
/**
* Stops and destroys this manager.
*/
~FinishedSignalThreadManager();
/**
* Adds a thread to this manager.
*
* @param inThread the thread to add.
* Will be destroyed by this class.
*/
void addThread( FinishedSignalThread *inThread );
// implements the Thread interface
void run();
protected:
MutexLock *mLock;
SimpleVector<FinishedSignalThread *> *mThreadVector;
char mStopSignal;
BinarySemaphore *mSleepSemaphore;
};
#endif

View file

@ -0,0 +1,51 @@
/*
* Modification History
*
* 2003-January-10 Jason Rohrer
* Created.
*/
#include "minorGems/common.h"
#ifndef LAUNCHER_INCLUDED
#define LAUNCHER_INCLUDED
/**
* Interface for launching processes.
*
* @author Jason Rohrer
*/
class Launcher {
public:
/**
* Launches a command in a new process.
*
* @param inCommandName the name of the command to launch.
* Must be destroyed by caller if non-const.
* @param inArguments an array of argument strings for the command.
* This array must be terminated by a NULL pointer.
* Note that by convention, the first argument should be the
* command name.
* Must be destroyed by caller.
*/
static void launchCommand( char *inCommandName,
char **inArguments );
};
#endif

View file

@ -0,0 +1,71 @@
/*
* Modification History
*
* 2000-December-13 Jason Rohrer
* Created.
*
* 2002-March-29 Jason Rohrer
* Added Fortify inclusion.
*
* 2002-October-18 Jason Rohrer
* Moved common include out of header and into platform-specific cpp files,
* since MemoryTrack uses a mutex lock.
*/
#ifndef MUTEX_LOCK_CLASS_INCLUDED
#define MUTEX_LOCK_CLASS_INCLUDED
#ifdef FORTIFY
#include "minorGems/util/development/fortify/fortify.h"
#endif
/**
* Mutex lock class.
*
* Note: Implementation for the functions defined here is provided
* separately for each platform (in the mac/ linux/ and win32/
* subdirectories).
*
* @author Jason Rohrer
*/
class MutexLock {
public:
/**
* Constructs a mutex lock;
*/
MutexLock();
~MutexLock();
/**
* Locks the mutex. Blocks until mutex available if it's
* already locked by another thread.
*/
void lock();
/**
* Unlocks the mutex.
*/
void unlock();
private:
/**
* Used by platform-specific implementations.
*/
void *mNativeObjectPointer;
};
#endif

View file

@ -0,0 +1,201 @@
/*
* Modification History
*
* 2001-January-11 Jason Rohrer
* Created.
*
* 2001-January-11 Jason Rohrer
* Added a willBlock() function.
*
* 2001-February-24 Jason Rohrer
* Fixed incorrect delete usage.
*
* 2002-February-11 Jason Rohrer
* Fixed a mistake in the signal() comment.
*
* 2003-August-26 Jason Rohrer
* Added support for timeouts on wait.
*
* 2003-December-28 Jason Rohrer
* Fixed a bug in semaphore value when we timeout on wait.
*
* 2004-January-9 Jason Rohrer
* Fixed a preprocessor error.
*/
#include "minorGems/common.h"
#ifndef SEMAPHORE_CLASS_INCLUDED
#define SEMAPHORE_CLASS_INCLUDED
#include "MutexLock.h"
#include "BinarySemaphore.h"
/**
* General semaphore with an unbounded value.
*
* This class uses BinarySemaphores to implement general semaphores,
* so it relies on platform-specific BinarySemaphore implementations,
* but this class itself is platform-independent.
*
* @author Jason Rohrer
*/
class Semaphore {
public:
/**
* Constructs a semaphore.
*
* @param inStartingValue the starting value for this semaphore.
* Defaults to 0 if unspecified.
*/
Semaphore( int inStartingValue = 0 );
~Semaphore();
/**
* If this semaphore's current value is 0, then this call blocks
* on this semaphore until signal() is called by another thread.
* If this semaphore's value is >0, then it is decremented by this
* call.
*
* @param inTimeoutInMilliseconds the maximum time to wait in
* milliseconds, or -1 to wait forever. Defaults to -1.
*
* @return 1 if the semaphore was signaled, or 0 if it timed out.
*/
int wait( int inTimeoutInMilliseconds = -1 );
/**
* If a thread is waiting on this semaphore, then the thread
* becomes unblocked.
* If no thread is waiting, then the semaphore is incremented.
*/
void signal();
/**
* Returns true if a call to wait would have blocked.
*/
char willBlock();
private:
// starts at 0
int mSemaphoreValue;
// mutex semaphore starts at 1
BinarySemaphore *mMutexSemaphore;
// blocking semaphore starts at 0
BinarySemaphore *mBlockingSemaphore;
};
inline Semaphore::Semaphore( int inStartingValue )
: mSemaphoreValue( inStartingValue ),
mMutexSemaphore( new BinarySemaphore() ),
mBlockingSemaphore( new BinarySemaphore() ) {
// increment the mutex semaphore to 1
mMutexSemaphore->signal();
}
inline Semaphore::~Semaphore() {
delete mMutexSemaphore;
delete mBlockingSemaphore;
}
inline int Semaphore::wait( int inTimeoutInMilliseconds ) {
int returnValue;
// this implementation copied from _Operating System Concepts_, p. 172
// lock the mutex
mMutexSemaphore->wait();
// decrement the semaphore
mSemaphoreValue--;
if( mSemaphoreValue < 0 ) {
// we should block
// release the mutex
mMutexSemaphore->signal();
// block
returnValue = mBlockingSemaphore->wait( inTimeoutInMilliseconds );
if( returnValue != 1 ) {
// timed out
// increment the semaphore, since we never got signaled
// lock the mutex
mMutexSemaphore->wait();
mSemaphoreValue++;
// we will unlock the mutex below
}
}
else {
returnValue = 1;
}
// release the mutex
// ( if we were signaled, then the signaller left the mutex locked )
// ( if we timed out, then we re-locked the mutex above )
mMutexSemaphore->signal();
return returnValue;
}
inline char Semaphore::willBlock() {
char returnValue = false;
// lock the mutex
mMutexSemaphore->wait();
// check if we will block
if( mSemaphoreValue <= 0 ) {
returnValue = true;
}
// release the mutex
mMutexSemaphore->signal();
return returnValue;
}
inline void Semaphore::signal() {
// lock the mutex
mMutexSemaphore->wait();
// increment the semaphore
mSemaphoreValue++;
if( mSemaphoreValue <= 0 ) {
// we need to wake up a waiting thread
mBlockingSemaphore->signal();
// let the waiting thread unlock the mutex
}
else {
// no threads are waiting, so we need to unlock the mutex
mMutexSemaphore->signal();
}
}
#endif

View file

@ -0,0 +1,65 @@
/*
* Modification History
*
* 2002-April-4 Jason Rohrer
* Created.
* Changed to reflect the fact that the base class
* destructor is called *after* the derived class destructor.
*
* 2002-August-5 Jason Rohrer
* Fixed member initialization order to match declaration order.
*
* 2003-September-5 Jason Rohrer
* Moved into minorGems.
*
* 2005-January-9 Jason Rohrer
* Changed to sleep on a semaphore to make sleep interruptable by stop.
*/
#include "StopSignalThread.h"
StopSignalThread::StopSignalThread()
: mStopLock( new MutexLock() ), mStopped( false ),
mSleepSemaphore( new BinarySemaphore() ) {
}
StopSignalThread::~StopSignalThread() {
delete mStopLock;
delete mSleepSemaphore;
}
void StopSignalThread::sleep( unsigned long inTimeInMilliseconds ) {
mSleepSemaphore->wait( inTimeInMilliseconds );
}
char StopSignalThread::isStopped() {
mStopLock->lock();
char stoped = mStopped;
mStopLock->unlock();
return stoped;
}
void StopSignalThread::stop() {
mStopLock->lock();
mStopped = true;
mStopLock->unlock();
// signal the semaphore to wake up the thread, if it is sleeping
mSleepSemaphore->signal();
}

View file

@ -0,0 +1,104 @@
/*
* Modification History
*
* 2002-April-4 Jason Rohrer
* Created.
* Changed to reflect the fact that the base class
* destructor is called *after* the derived class destructor.
*
* 2003-September-5 Jason Rohrer
* Moved into minorGems.
*
* 2004-November-19 Jason Rohrer
* Changed to virtual inheritance from Thread class.
*
* 2005-January-9 Jason Rohrer
* Changed to sleep on a semaphore to make sleep interruptable by stop.
*/
#ifndef STOP_SIGNAL_THREAD_INCLUDED
#define STOP_SIGNAL_THREAD_INCLUDED
#include "minorGems/system/Thread.h"
#include "minorGems/system/MutexLock.h"
#include "minorGems/system/BinarySemaphore.h"
/**
* Abstract subclass of thread that has a stop signal.
*
* Note that subclasses MUST check the isStopped() function
* periodically in their run() function for this class to work
* properly.
*
* @author Jason Rohrer
*/
class StopSignalThread : public virtual Thread {
public:
/**
* Only destroys this thread.
* Does not stop or join.
*/
virtual ~StopSignalThread();
protected:
StopSignalThread();
// overrides Thread::sleep to make it interruptable by our stop call
virtual void sleep( unsigned long inTimeInMilliseconds );
/**
* Signals this thread to stop, interrupting it if it is sleeping.
*
* Thread safe.
*
* Thread must be joined after this call returns.
*/
void stop();
/**
* Gets whether this thread has been signaled to stop.
*
* Thread safe.
*
* @return true if this thread should stop.
*/
char isStopped();
private:
MutexLock *mStopLock;
char mStopped;
BinarySemaphore *mSleepSemaphore;
};
#endif

View file

@ -0,0 +1,54 @@
/*
* Modification History
*
* 2000-December-13 Jason Rohrer
* Created.
*
* 2002-November-14 Jason Rohrer
* Added more verbose printouts.
*
* 2004-March-31 Jason Rohrer
* Added test of detached threads.
*/
#include "TestThread.h"
int numToCount = 1000;
/**
* Main method that spawns two TestThreads.
*
* @author Jason Rohrer
*/
int main() {
TestThread *thread1 = new TestThread( 1, numToCount );
TestThread *thread2 = new TestThread( 2, numToCount );
TestThread *thread3 = new TestThread( 3, numToCount );
ThreadSafePrinter::printf( "Starting thread 1\n" );
thread1->start();
ThreadSafePrinter::printf( "Starting thread 2\n" );
thread2->start();
ThreadSafePrinter::printf( "Starting thread 3 in detached mode\n" );
thread3->start( true );
Thread::sleep( 5000 );
ThreadSafePrinter::printf( "Joining thread 1\n" );
thread1->join();
ThreadSafePrinter::printf( "Joining thread 2\n" );
thread2->join();
ThreadSafePrinter::printf( "Destroying thread 1\n" );
delete thread1;
ThreadSafePrinter::printf( "Destroying thread 2\n" );
delete thread2;
ThreadSafePrinter::printf(
"Thread 3 should handle its own destruction.\n" );
return 0;
}

View file

@ -0,0 +1,77 @@
/*
* Modification History
*
* 2000-December-13 Jason Rohrer
* Created.
*
* 2001-January-27 Jason Rohrer
* Switched to a ThreadSafePrinter in attempt to get it to work on Win32.
* Changed print call to printf.
*
* 2002-November-14 Jason Rohrer
* Added missing destructor.
*/
#include "minorGems/common.h"
#ifndef TEST_THREAD_CLASS_INCLUDED
#define TEST_THREAD_CLASS_INCLUDED
#include "Thread.h"
#include "ThreadSafePrinter.h"
#include <stdio.h>
/**
* Test subclass of Thread class. Useful for testing if platform-specific
* thread implmentations are working.
*
* @author Jason Rohrer
*/
class TestThread : public Thread {
public:
/**
* Constructs a test thread and tells it how high to count to.
*
* @param inID id number thread will print along with count.
* @param inNumToCount thread will count from 0 to this number.
*/
TestThread( int inID, int inNumToCount );
~TestThread();
// override the run method from PThread
void run();
private:
int mID;
int mNumToCount;
};
inline TestThread::TestThread( int inID, int inNumToCount )
: mID( inID ), mNumToCount( inNumToCount ) {
}
inline TestThread::~TestThread() {
}
inline void TestThread::run() {
for( int i=0; i<=mNumToCount; i++ ) {
ThreadSafePrinter::printf( "Thread %d counting %d.\n", mID, i );
}
}
#endif

136
minorGems/system/Thread.h Normal file
View file

@ -0,0 +1,136 @@
/*
* Modification History
*
* 2000-December-13 Jason Rohrer
* Created.
*
* 2001-March-4 Jason Rohrer
* Made sleep() static so it can be called by non-Thread classes.
*
* 2001-May-12 Jason Rohrer
* Added comments about joining before destroying.
*
* 2002-March-29 Jason Rohrer
* Added Fortify inclusion.
*
* 2002-August-5 Jason Rohrer
* Made destructor virtual.
*
* 2004-March-31 Jason Rohrer
* Added support for detatched mode.
*
* 2005-January-9 Jason Rohrer
* Made sleep function virtual to allow overrides.
*
* 2005-January-22 Jason Rohrer
* Added a static sleep function.
*/
#include "minorGems/common.h"
#ifndef THREAD_CLASS_INCLUDED
#define THREAD_CLASS_INCLUDED
#ifdef FORTIFY
#include "minorGems/util/development/fortify/fortify.h"
#endif
/**
* Base class to be subclassed by all threads.
*
* Note: Implementation for the functions defined here is provided
* separately for each platform (in the mac/ linux/ and win32/
* subdirectories).
*
* @author Jason Rohrer
*/
class Thread {
public:
Thread();
virtual ~Thread();
/**
* Starts this Thread.
*
* Note that after starting a non-detached thread, it _must_ be
* joined before being destroyed to avoid memory leaks.
*
* Threads running in detatched mode handle their own destruction
* as they terminate and do not need to be joined at all.
*
* @param inDetach true if this thread should run in detatched mode,
* or false to run in non-detached mode. Defaults to false.
*/
void start( char inDetach = false );
/**
* To be overriden by subclasses.
* This method will be run by the Thread after start() has been called.
*/
virtual void run() = 0;
/**
* Blocks until this thread finishes executing its run() method.
*
* Must be called before destroying this thread, if this thread
* has been started.
*/
void join();
/**
* Puts the current thread to sleep for a specified amount of time.
*
* Note that given a thread instance threadA, calling threadA.sleep()
* will put the calling thread to sleep.
*
* @param inTimeInMilliseconds the number of milliseconds to sleep.
*/
virtual void sleep( unsigned long inTimeInMilliseconds ) {
staticSleep( inTimeInMilliseconds );
}
/**
* Same as sleep, but can be called without constructing a thread.
*/
static void staticSleep( unsigned long inTimeInMilliseconds );
/**
* Gets whether this thread is detached.
*
* @return true if this thread is detached.
*/
char isDetatched() {
return mIsDetached;
}
private:
/**
* Used by platform-specific implementations.
*/
void *mNativeObjectPointer;
char mIsDetached;
};
#endif

View file

@ -0,0 +1,71 @@
/*
* Modification History
*
* 2000-October-14 Jason Rohrer
* Created.
*
* 2001-January-27 Jason Rohrer
* Converted to use MutexLock and added to minorGems source tree.
* Changed tprintf to be static (the mutexes don't work otherwise).
* Now we're closing the argument list.
* Fixed so that it works with any number of arguments.
* Changed name of print function to printf.
*
* 2004-March-31 Jason Rohrer
* Fixed static memory leak.
*/
#include "minorGems/common.h"
#ifndef THREAD_SAFE_PRINTER_INCLUDED
#define THREAD_SAFE_PRINTER_INCLUDED
#include "MutexLock.h"
#include <stdio.h>
// for variable argument lists
#include <stdarg.h>
/**
* Thread safe printf function. Note that printf is actually thread safe
* anyway, so this is just to demonstrate and test locks. It seems as
* though printf _isn't_ thread safe on certain platforms, so this class
* may be useful.
*
* @author Jason Rohrer
*/
class ThreadSafePrinter {
public:
static int printf( const char* inFormatString, ... );
private:
static MutexLock sLock;
};
// initialize static members
MutexLock ThreadSafePrinter::sLock;
inline int ThreadSafePrinter::printf( const char*inFormatString, ... ) {
va_list argList;
va_start( argList, inFormatString );
sLock.lock();
int returnVal = vprintf( inFormatString, argList );
fflush( stdout );
sLock.unlock();
va_end( argList );
return returnVal;
}
#endif

112
minorGems/system/Time.h Normal file
View file

@ -0,0 +1,112 @@
/*
* Modification History
*
* 2001-October-29 Jason Rohrer
* Created.
*
* 2004-October-14 Jason Rohrer
* Fixed sign bug.
*
* 2005-February-10 Jason Rohrer
* Added function to get time in floating point format.
*/
#include "minorGems/common.h"
#ifndef TIME_INCLUDED
#define TIME_INCLUDED
/**
* Interface for platform-independent, high-resolution time access.
*
* @author Jason Rohrer
*/
class Time {
public:
/**
* Gets the current time in seconds and milliseconds.
*
* No guarentee about when absolute 0 of this time
* scale is for particular systems.
*
* @param outSeconds pointer to where the time in seconds
* will be returned.
* @param outMilliseconds pointer to where the extra
* milliseconds will be returned. Value returned is in [0,999].
*/
static void getCurrentTime( unsigned long *outSeconds,
unsigned long *outMilliseconds );
/**
* Gets the current time in fractional (double) seconds.
*
* @return the current time in seconds.
*/
static double getCurrentTime();
/**
* Gets the number of milliseconds that have passed
* since a time in seconds and milliseconds.
*
* @param inSeconds the start time, in seconds.
* @param inMilliseconds the start time's additional milliseconds.
*
* @return the number of milliseconds that have passed
* since inSeconds:inMilliseconds. May overflow if
* more than 49 days have passed (assuming 32-bit longs).
*/
static unsigned long getMillisecondsSince(
unsigned long inSeconds, unsigned long inMilliseconds );
};
inline double Time::getCurrentTime() {
unsigned long currentTimeS;
unsigned long currentTimeMS;
getCurrentTime( &currentTimeS, &currentTimeMS );
return currentTimeS + currentTimeMS / 1000.0;
}
inline unsigned long Time::getMillisecondsSince(
unsigned long inSeconds, unsigned long inMilliseconds ) {
unsigned long currentTimeS;
unsigned long currentTimeMS;
getCurrentTime( &currentTimeS, &currentTimeMS );
unsigned long deltaS = ( currentTimeS - inSeconds );
long deltaMS = ( (long)currentTimeMS - (long)inMilliseconds );
// carry, if needed
if( deltaMS < 0 ) {
deltaS--;
deltaMS += 1000;
}
return 1000 * deltaS + deltaMS;
}
#endif

108
minorGems/system/endian.h Normal file
View file

@ -0,0 +1,108 @@
/*
* Modification History
*
* 2002-May-25 Jason Rohrer
* Created.
*
* 2004-January-12 Jason Rohrer
* Added support for metrowerks win32 compiler.
*
* 2009-April-3 Jason Rohrer
* OpenBSD support.
*/
#include "minorGems/common.h"
/**
* Include this file to define __BYTE_ORDER
*
* After this has been included, __BYTE_ORDER will be either
* __LITTLE_ENDIAN or
* __BIG_ENDIAN
*/
#ifdef __FreeBSD__
#include <machine/endian.h>
#elif defined(__NetBSD__)
#include <sys/endian.h>
#elif defined(__OpenBSD__)
#include <sys/types.h>
#include <machine/endian.h>
// default BSD case
#elif defined(BSD)
#include <machine/endian.h>
#elif defined(SOLARIS)
// Code for Solaris defs adapted from:
// MD5 message-digest algorithm.
// by Colin Plumb in 1993, no copyright is claimed.
//each solaris is different -- this won't work on 2.6 or 2.7
# include <sys/isa_defs.h>
#define __LITTLE_ENDIAN 1234
#define __BIG_ENDIAN 4321
#ifdef _LITTLE_ENDIAN
#define __BYTE_ORDER __LITTLE_ENDIAN
#else // default to big endian
#define __BYTE_ORDER __BIG_ENDIAN
#endif
// end solaris case
#elif defined(WIN_32) || \
( defined(__MWERKS__) && defined(__INTEL__) ) // windows case
#define __LITTLE_ENDIAN 1234
#define __BYTE_ORDER __LITTLE_ENDIAN
// end windows case
#else
// linux case
#include <endian.h>
// end linux case
#endif
// end of all system-specific cases
// BSD calls it BYTE_ORDER, linux calls it __BYTE_ORDER
#ifndef __BYTE_ORDER
#define __BYTE_ORDER BYTE_ORDER
#endif
#ifndef __LITTLE_ENDIAN
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#endif
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN BIG_ENDIAN
#endif

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

View file

@ -0,0 +1,115 @@
/*
* Modification History
*
* 2001-January-11 Jason Rohrer
* Created.
*
* 2001-January-27 Jason Rohrer
* Made printing in threads thread-safe.
*/
#include "BinarySemaphore.h"
#include "Semaphore.h"
#include "Thread.h"
#include "ThreadSafePrinter.h"
#include <stdio.h>
/**
* Thread that waits on a semaphore.
*
* @author Jason Rohrer
*/
class WaitingThread : public Thread {
public:
WaitingThread( int inID, Semaphore *inSemaphore );
// override the run method from PThread
void run();
private:
Semaphore *mSemaphore;
int mID;
};
inline WaitingThread::WaitingThread( int inID, Semaphore *inSemaphore )
: mID( inID ), mSemaphore( inSemaphore ) {
}
inline void WaitingThread::run() {
for( int i=0; i<10; i++ ) {
ThreadSafePrinter::printf( "%d waiting for signal %d...\n", mID, i );
mSemaphore->wait();
ThreadSafePrinter::printf( "%d received signal %d.\n", mID, i );
}
}
/**
* Thread that signals on a semaphore.
*
* @author Jason Rohrer
*/
class SignalingThread : public Thread {
public:
SignalingThread( Semaphore *inSemaphore );
// override the run method from PThread
void run();
private:
Semaphore *mSemaphore;
};
inline SignalingThread::SignalingThread( Semaphore *inSemaphore )
: mSemaphore( inSemaphore ) {
}
inline void SignalingThread::run() {
for( int i=0; i<5; i++ ) {
sleep( 5000 );
ThreadSafePrinter::printf( "Signaling 20 times\n" );
for( int j=0; j<20; j++ ) {
mSemaphore->signal();
}
}
}
int main() {
int i;
Semaphore *semph = new Semaphore();
SignalingThread *threadS = new SignalingThread( semph );
WaitingThread **threadW = new WaitingThread*[10];
for( i=0; i<10; i++ ) {
threadW[i] = new WaitingThread( i, semph );
threadW[i]->start();
}
threadS->start();
for( i=0; i<10; i++ ) {
threadW[i]->join();
delete threadW[i];
}
threadS->join();
delete semph;
delete threadS;
delete [] threadW;
return 0;
}

View file

@ -0,0 +1,33 @@
/*
* Modification History
*
* 2003-January-10 Jason Rohrer
* Created.
*/
#include "minorGems/system/Launcher.h"
#include <unistd.h>
#include <stdarg.h>
void Launcher::launchCommand( char *inCommandName,
char **inArguments ) {
int forkValue = fork();
if( forkValue == 0 ) {
// we're in child process, so exec command
execvp( inCommandName, inArguments );
// we'll never return from this call
}
}

View file

@ -0,0 +1,40 @@
/*
* Modification History
*
* 2001-October-29 Jason Rohrer
* Created.
*
* 2002-March-13 Jason Rohrer
* Added include of time.h so that FreeBSD compile will work.
* Changed to use newer gettimeofday that should work on all unix platforms.
* Fixed a conversion bug.
*/
#include "minorGems/system/Time.h"
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
void Time::getCurrentTime( unsigned long *outSeconds,
unsigned long *outMilliseconds ) {
struct timeval currentTime;
gettimeofday( &currentTime, NULL );
*outMilliseconds = currentTime.tv_usec / 1000;
*outSeconds = currentTime.tv_sec;
}

View file

@ -0,0 +1,94 @@
/*
* Modification History
*
* 2001-January-27 Jason Rohrer
* Created.
*
* 2001-March-4 Jason Rohrer
* Replaced include of <winbase.h> and <windef.h> with <windows.h>
* to fix compile bugs encountered with newer windows compilers.
*
* 2003-August-26 Jason Rohrer
* Added support for timeouts on wait.
*/
#include "minorGems/system/BinarySemaphore.h"
#include <windows.h>
/**
* Win32-specific implementation of the BinarySemaphore class member functions.
*/
/**
* Native object pointer A is the semaphore handle.
* Pointer B is not used.
*/
BinarySemaphore::BinarySemaphore() :
mSemaphoreValue( 0 ) {
// allocate a handle on the heap
mNativeObjectPointerA = (void *)( new HANDLE[1] );
// retrieve handle from the heap
HANDLE *semaphorePointer = (HANDLE *)mNativeObjectPointerA;
semaphorePointer[0] = CreateSemaphore(
(LPSECURITY_ATTRIBUTES) NULL, // no attributes
0, // initial count
1, // maximum count
(LPCTSTR) NULL ); // no name
}
BinarySemaphore::~BinarySemaphore() {
// retrieve handle from the heap
HANDLE *semaphorePointer = (HANDLE *)mNativeObjectPointerA;
// destroy the semaphore
CloseHandle( semaphorePointer[0] );
// de-allocate the handle from the heap
delete [] semaphorePointer;
}
int BinarySemaphore::wait( int inTimeoutInMilliseconds ) {
// retrieve handle from the heap
HANDLE *semaphorePointer = (HANDLE *)mNativeObjectPointerA;
if( inTimeoutInMilliseconds == -1 ) {
WaitForSingleObject( semaphorePointer[0], INFINITE );
return 1;
}
else {
// timeout
int result = WaitForSingleObject( semaphorePointer[0],
inTimeoutInMilliseconds );
if( result == WAIT_TIMEOUT ) {
return 0;
}
else {
return 1;
}
}
}
void BinarySemaphore::signal() {
// retrieve handle from the heap
HANDLE *semaphorePointer = (HANDLE *)mNativeObjectPointerA;
ReleaseSemaphore( semaphorePointer[0], 1, (LPLONG) NULL );
}

View file

@ -0,0 +1,29 @@
/*
* Modification History
*
* 2003-January-10 Jason Rohrer
* Created.
*
* 2003-March-24 Jason Rohrer
* Fixed a syntax typo.
*/
#include "minorGems/system/Launcher.h"
#include <windows.h>
#include <process.h>
void Launcher::launchCommand( char *inCommandName,
char **inArguments ) {
_spawnvp( _P_NOWAIT,
inCommandName,
inArguments );
}

View file

@ -0,0 +1,81 @@
/*
* Modification History
*
* 2001-January-27 Jason Rohrer
* Created.
*
* 2001-March-4 Jason Rohrer
* Replaced include of <winbase.h> and <windef.h> with <windows.h>
* to fix compile bugs encountered with newer windows compilers.
*
* 2002-October-18 Jason Rohrer
* Moved common include out of header and into platform-specific cpp files,
* since MemoryTrack uses a mutex lock.
*
* 2002-October-19 Jason Rohrer
* Changed to use malloc instead of new internally to work with debugMemory.
* Made use of mNativeObjectPointer a bit cleaner.
* Fixed a few bugs with new use of mNativeObjectPointer.
*/
#include "minorGems/common.h"
#include "minorGems/system/MutexLock.h"
#include <windows.h>
#include <stdlib.h>
/**
* Win32-specific implementation of the MutexLock class member functions.
*/
MutexLock::MutexLock() {
// allocate a handle on the heap
mNativeObjectPointer = malloc( sizeof( HANDLE ) );
// retrieve handle from the heap
HANDLE *mutexPointer = (HANDLE *)mNativeObjectPointer;
// create the mutex
*mutexPointer = CreateMutex(
(LPSECURITY_ATTRIBUTES) NULL, // no attributes
(BOOL) false, // not initially locked
(LPCTSTR) NULL ); // no name
}
MutexLock::~MutexLock() {
// retrieve handle from the heap
HANDLE *mutexPointer = (HANDLE *)mNativeObjectPointer;
// destroy the mutex
CloseHandle( *mutexPointer );
// de-allocate the mutex structure from the heap
free( mutexPointer );
}
void MutexLock::lock() {
// retrieve handle from the heap
HANDLE *mutexPointer = (HANDLE *)mNativeObjectPointer;
WaitForSingleObject( *mutexPointer, INFINITE );
}
void MutexLock::unlock() {
// retrieve handle from the heap
HANDLE *mutexPointer = (HANDLE *)mNativeObjectPointer;
ReleaseMutex( *mutexPointer );
}

View file

@ -0,0 +1,108 @@
/*
* Modification History
*
* 2001-January-27 Jason Rohrer
* Created.
*
* 2001-March-4 Jason Rohrer
* Replaced include of <winbase.h> and <windef.h> with <windows.h>
* to fix compile bugs encountered with newer windows compilers.
*
* 2004-March-31 Jason Rohrer
* Added missing call to CloseHandle in destructor.
* Added support for detatched mode.
*
* 2004-April-1 Jason Rohrer
* Fixed a bug in CloseHandle call pointed out by Mycroftxxx.
*
* 2005-January-22 Jason Rohrer
* Added a static sleep function.
*/
#include "minorGems/system/Thread.h"
#include <windows.h>
/**
* Win32-specific implementation of the Thread class member functions.
*
*/
// prototype
/**
* A wrapper for the run method, since windows thread (perhaps) won't take
* a class's member function. Takes a pointer to the Thread to run,
* cast as a void*;
*/
DWORD WINAPI win32ThreadFunction( void * );
Thread::Thread() {
// allocate a handle on the heap
mNativeObjectPointer = (void *)( new HANDLE[1] );
}
Thread::~Thread() {
// get a pointer to the allocated handle
HANDLE *threadPointer = (HANDLE *)mNativeObjectPointer;
// close the handle to ensure that the thread resources are freed
CloseHandle( threadPointer[0] );
// de-allocate the thread handle from the heap
delete [] threadPointer;
}
void Thread::start( char inDetach ) {
mIsDetached = inDetach;
// get a pointer to the allocated handle
HANDLE *threadPointer = (HANDLE *)mNativeObjectPointer;
DWORD threadID;
threadPointer[0] = CreateThread(
(LPSECURITY_ATTRIBUTES)NULL, // no attributes
(DWORD)0, // default stack size
win32ThreadFunction, // function
(LPVOID)this, // function arg
(DWORD)0, // no creation flags (start thread immediately)
&threadID );
}
void Thread::join() {
HANDLE *threadPointer = (HANDLE *)mNativeObjectPointer;
WaitForSingleObject( threadPointer[0], INFINITE );
}
void Thread::staticSleep( unsigned long inTimeInMilliseconds ) {
Sleep( inTimeInMilliseconds );
}
// takes a pointer to a Thread object as the data value
DWORD WINAPI win32ThreadFunction( void *inPtrToThread ) {
Thread *threadToRun = (Thread *)inPtrToThread;
threadToRun->run();
if( threadToRun->isDetatched() ) {
// thread detached, so we must destroy it
delete threadToRun;
}
return 0;
}

View file

@ -0,0 +1,77 @@
/*
* Modification History
*
* 2001-November-7 Jason Rohrer
* Created.
*
* 2002-April-11 Jason Rohrer
* Added missing include, and fixed a bug.
*
* 2004-January-29 Jason Rohrer
* Fixed so that 0-point of time is the same as on other platforms.
*
* 2004-October-14 Jason Rohrer
* Fixed bug in second/millisecond callibration.
* Fixed bug in win32 time to ANSI time translation.
* Fixed daylight savings time bug.
*/
#include "minorGems/system/Time.h"
#include <windows.h>
#include <winbase.h>
#include <time.h>
#include <stdio.h>
/**
* Windows implementation of Time.h.
*
* The 0-point should match the ANSI standard.
*/
void Time::getCurrentTime( unsigned long *outSeconds,
unsigned long *outMilliseconds ) {
// convert from win32 broken-down time (which has msec resolution)
// to an ANSI time struct and then convert to an absolute time in
// seconds
// This procedure ensures that the 0-point matches the ANSI standard.
// note:
// we cannot simply call ANSI time() to get the seconds and then rely
// on GetLocalTime to get the milliseconds, since the seconds value
// used by GetLocalTime is (strangely enough) not calibrated to the seconds
// value of time().
// In other words, it is possible for the time() seconds to advance
// at a different clock cycle than the GetLocalTime seconds.
// get time using a win32 call
SYSTEMTIME win32TimeStruct;
GetLocalTime( &win32TimeStruct );
// convert this win32 structure to the ANSI standard structure
struct tm ansiTimeStruct;
ansiTimeStruct.tm_sec = win32TimeStruct.wSecond;
ansiTimeStruct.tm_min = win32TimeStruct.wMinute;
ansiTimeStruct.tm_hour = win32TimeStruct.wHour;
ansiTimeStruct.tm_mday = win32TimeStruct.wDay;
// ANSI time struct has month in range [0..11]
ansiTimeStruct.tm_mon = win32TimeStruct.wMonth - 1;
// ANSI time struct has year that is an offset from 1900
ansiTimeStruct.tm_year = win32TimeStruct.wYear - 1900;
// unknown daylight savings time (dst) status
// if we fail to init this value, we can get inconsistent results
ansiTimeStruct.tm_isdst = -1;
unsigned long secondsSinceEpoch = mktime( &ansiTimeStruct );
*outSeconds = secondsSinceEpoch;
*outMilliseconds = (unsigned long)( win32TimeStruct.wMilliseconds );
}