diff --git a/include/OpenThreads/Barrier b/include/OpenThreads/Barrier new file mode 100644 index 000000000..663d198f1 --- /dev/null +++ b/include/OpenThreads/Barrier @@ -0,0 +1,100 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Barrier - C++ barrier class +// ~~~~~~~ +// + +#ifndef _OPENTHREADS_BARRIER_ +#define _OPENTHREADS_BARRIER_ + +#include + +namespace OpenThreads { + + +/** + * @class Barrier + * @brief This class provides an object-oriented thread barrier interface + * + * @warning It is unwise to use the construct "Barrier barrier" in the + * global namespace on sgi's. The object "barrier" + * will confilict with the c-library sproc function "barrier" and + * unpredictable results may occur. You have been warned. + */ +class OPENTHREAD_EXPORT_DIRECTIVE Barrier { + +public: + + /** + * Constructor + */ + Barrier(int numThreads=0); + + /** + * Destructor + */ + virtual ~Barrier(); + + /** + * Reset the barrier to it's original state. + */ + virtual void reset(); + + /** + * Block until numThreads threads have entered the barrier. + */ + virtual void block(unsigned int numThreads=0); + + /** + * Release the barrier, now. + */ + virtual void release(); + + /** + * Return the number of threads currently blocked in the barrier, + * Return -1 if error. + */ + virtual int numThreadsCurrentlyBlocked(); + + + void invalidate(); + +private: + + /** + * Private copy constructor, to prevent tampering. + */ + Barrier(const Barrier &/*b*/) {}; + + /** + * Private copy assignment, to prevent tampering. + */ + Barrier &operator=(const Barrier &/*b*/) {return *(this);}; + + /** + * Implementation-specific private data. + */ + void *_prvData; + + + bool _valid; + +}; + +} + +#endif // !_OPENTHREADS_BARRIER_ + diff --git a/include/OpenThreads/Block b/include/OpenThreads/Block new file mode 100644 index 000000000..0b821e4ed --- /dev/null +++ b/include/OpenThreads/Block @@ -0,0 +1,177 @@ +/* -*-c++-*- OpenThreads - Copyright (C) 1998-2007 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef _OPENTHREADS_BLOCK_ +#define _OPENTHREADS_BLOCK_ + +#include +#include +#include +#include + +namespace OpenThreads { + +/** Block is a block that can be used to halt a thread that is waiting another thread to release it.*/ +class Block +{ + public: + + Block(): + _released(false) {} + + ~Block() + { + release(); + } + + inline bool block() + { + ScopedLock mutlock(_mut); + if( !_released ) + { + return _cond.wait(&_mut)==0; + } + else + { + return true; + } + } + + inline bool block(unsigned long timeout) + { + ScopedLock mutlock(_mut); + if( !_released ) + { + return _cond.wait(&_mut, timeout)==0; + } + else + { + return true; + } + } + + inline void release() + { + ScopedLock mutlock(_mut); + if (!_released) + { + _released = true; + _cond.broadcast(); + } + } + + inline void reset() + { + ScopedLock mutlock(_mut); + _released = false; + } + + inline void set(bool doRelease) + { + if (doRelease!=_released) + { + if (doRelease) release(); + else reset(); + } + } + + protected: + + Mutex _mut; + Condition _cond; + bool _released; + + private: + + Block(const Block&) {} +}; + +/** BlockCount is a block that can be used to halt a thread that is waiting for a specified number of operations to be completed.*/ +class BlockCount +{ + public: + + BlockCount(unsigned int blockCount): + _blockCount(blockCount), + _currentCount(0) {} + + ~BlockCount() + { + _blockCount = 0; + release(); + } + + inline void completed() + { + OpenThreads::ScopedLock mutlock(_mut); + if (_currentCount>0) + { + --_currentCount; + + if (_currentCount==0) + { + // osg::notify(osg::NOTICE)<<"Released"< mutlock(_mut); + if (_currentCount) + _cond.wait(&_mut); + } + + inline void reset() + { + OpenThreads::ScopedLock mutlock(_mut); + if (_currentCount!=_blockCount) + { + if (_blockCount==0) _cond.broadcast(); + _currentCount = _blockCount; + } + } + + inline void release() + { + OpenThreads::ScopedLock mutlock(_mut); + if (_currentCount) + { + _currentCount = 0; + _cond.broadcast(); + } + } + + inline void setBlockCount(unsigned int blockCount) { _blockCount = blockCount; } + + inline unsigned int getBlockCount() const { return _blockCount; } + + inline unsigned int getCurrentCount() const { return _currentCount; } + + protected: + + OpenThreads::Mutex _mut; + OpenThreads::Condition _cond; + unsigned int _blockCount; + unsigned int _currentCount; + + private: + + BlockCount(const BlockCount&) {} + +}; + +} + +#endif diff --git a/include/OpenThreads/Condition b/include/OpenThreads/Condition new file mode 100644 index 000000000..454c079d3 --- /dev/null +++ b/include/OpenThreads/Condition @@ -0,0 +1,93 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Condition - C++ condition class +// ~~~~~~~~~ +// + +#ifndef _OPENTHREADS_CONDITION_ +#define _OPENTHREADS_CONDITION_ + +#include +#include + +namespace OpenThreads { + +/** + * @class Condition + * @brief This class provides an object-oriented thread condition interface. + */ +class OPENTHREAD_EXPORT_DIRECTIVE Condition { + +public: + + /** + * Constructor + */ + Condition(); + + /** + * Destructor + */ + virtual ~Condition(); + + /** + * Wait on a mutex. + */ + virtual int wait(Mutex *mutex); + + /** + * Wait on a mutex for a given amount of time (ms) + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int wait(Mutex *mutex, unsigned long int ms); + + /** + * Signal a SINGLE thread to wake if it's waiting. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int signal(); + + /** + * Wake all threads waiting on this condition. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int broadcast(); + +private: + + /** + * Private copy constructor, to prevent tampering. + */ + Condition(const Condition &/*c*/) {}; + + /** + * Private copy assignment, to prevent tampering. + */ + Condition &operator=(const Condition &/*c*/) {return *(this);}; + + /** + * Implementation-specific data + */ + void *_prvData; + +}; + +} + +#endif // !_OPENTHREADS_CONDITION_ diff --git a/include/OpenThreads/Exports b/include/OpenThreads/Exports new file mode 100644 index 000000000..b388ee079 --- /dev/null +++ b/include/OpenThreads/Exports @@ -0,0 +1,43 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef _OPENTHREAD_EXPORTS_H_ +#define _OPENTHREAD_EXPORTS_H_ + + +#ifndef WIN32 + #define OPENTHREAD_EXPORT_DIRECTIVE +#else + #if defined( OT_LIBRARY_STATIC ) + #define OPENTHREAD_EXPORT_DIRECTIVE + #elif defined( OPENTHREADS_EXPORTS ) + #define OPENTHREAD_EXPORT_DIRECTIVE __declspec(dllexport) + #else + #define OPENTHREAD_EXPORT_DIRECTIVE __declspec(dllimport) + + #if 0 // Commented out for now + + #ifdef _MSC_VER + #ifdef _DEBUG + #pragma comment(lib ,"OpenThreadsWin32d") + #else + #pragma comment(lib, "OpenThreadsWin32") + #endif + #endif + #endif + #endif +#endif + +#endif + + diff --git a/include/OpenThreads/Mutex b/include/OpenThreads/Mutex new file mode 100644 index 000000000..df8c4abf1 --- /dev/null +++ b/include/OpenThreads/Mutex @@ -0,0 +1,89 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Mutex - C++ mutex class +// ~~~~~ +// + +#ifndef _OPENTHREADS_MUTEX_ +#define _OPENTHREADS_MUTEX_ + +#include + +namespace OpenThreads { + +/** + * @class Mutex + * @brief This class provides an object-oriented thread mutex interface. + */ +class OPENTHREAD_EXPORT_DIRECTIVE Mutex { + + friend class Condition; + +public: + + /** + * Constructor + */ + Mutex(); + + /** + * Destructor + */ + virtual ~Mutex(); + + /** + * Lock the mutex + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int lock(); + + /** + * Unlock the mutex + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int unlock(); + + /** + * Test if mutex can be locked. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int trylock(); + +private: + + /** + * Private copy constructor, to prevent tampering. + */ + Mutex(const Mutex &/*m*/) {}; + + /** + * Private copy assignment, to prevent tampering. + */ + Mutex &operator=(const Mutex &/*m*/) {return *(this);}; + + /** + * Implementation-specific private data. + */ + void *_prvData; + +}; + +} + +#endif // _OPENTHREADS_MUTEX_ diff --git a/include/OpenThreads/ReadWriteMutex b/include/OpenThreads/ReadWriteMutex new file mode 100644 index 000000000..83bc75ddb --- /dev/null +++ b/include/OpenThreads/ReadWriteMutex @@ -0,0 +1,110 @@ +/* -*-c++-*- OpenThreads - Copyright (C) 1998-2007 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef _OPENTHREADS_READWRITEMUTEX_ +#define _OPENTHREADS_READWRITEMUTEX_ + +#include +#include + +namespace OpenThreads { + +class ReadWriteMutex +{ + public: + + ReadWriteMutex(): + _readCount(0) {} + + virtual ~ReadWriteMutex() {} + + virtual int readLock() + { + OpenThreads::ScopedLock lock(_readCountMutex); + int result = 0; + if (_readCount==0) + { + result = _readWriteMutex.lock(); + } + ++_readCount; + return result; + } + + + virtual int readUnlock() + { + OpenThreads::ScopedLock lock(_readCountMutex); + int result = 0; + if (_readCount>0) + { + --_readCount; + if (_readCount==0) + { + result = _readWriteMutex.unlock(); + } + } + return result; + } + + virtual int writeLock() + { + return _readWriteMutex.lock(); + } + + virtual int writeUnlock() + { + return _readWriteMutex.unlock(); + } + + protected: + + ReadWriteMutex(const ReadWriteMutex&) {} + ReadWriteMutex& operator = (const ReadWriteMutex&) { return *(this); } + +#if 0 + ReentrantMutex _readWriteMutex; + ReentrantMutex _readCountMutex; +#else + OpenThreads::Mutex _readWriteMutex; + OpenThreads::Mutex _readCountMutex; +#endif + unsigned int _readCount; + +}; + +class ScopedReadLock +{ + public: + + ScopedReadLock(ReadWriteMutex& mutex):_mutex(mutex) { _mutex.readLock(); } + ~ScopedReadLock() { _mutex.readUnlock(); } + + protected: + ReadWriteMutex& _mutex; +}; + + +class ScopedWriteLock +{ + public: + + ScopedWriteLock(ReadWriteMutex& mutex):_mutex(mutex) { _mutex.writeLock(); } + ~ScopedWriteLock() { _mutex.writeUnlock(); } + + protected: + ReadWriteMutex& _mutex; +}; + +} + +#endif diff --git a/include/OpenThreads/ReentrantMutex b/include/OpenThreads/ReentrantMutex new file mode 100644 index 000000000..8dae6a7aa --- /dev/null +++ b/include/OpenThreads/ReentrantMutex @@ -0,0 +1,125 @@ +/* -*-c++-*- OpenThreads - Copyright (C) 1998-2007 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef _OPENTHREADS_REENTRANTMUTEX_ +#define _OPENTHREADS_REENTRANTMUTEX_ + +#include +#include +#include + +namespace OpenThreads { + +class ReentrantMutex : public OpenThreads::Mutex +{ + public: + + ReentrantMutex(): + _threadHoldingMutex(0), + _lockCount(0) {} + + virtual ~ReentrantMutex() {} + + virtual int lock() + { + if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0) + { + OpenThreads::ScopedLock lock(_lockCountMutex); + ++_lockCount; + return 0; + } + else + { + int result = Mutex::lock(); + if (result==0) + { + OpenThreads::ScopedLock lock(_lockCountMutex); + + _threadHoldingMutex = OpenThreads::Thread::CurrentThread(); + _lockCount = 1; + } + return result; + } + } + + + virtual int unlock() + { + OpenThreads::ScopedLock lock(_lockCountMutex); + #if 0 + if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0) + { + --_lockCount; + if (_lockCount<=0) + { + _threadHoldingMutex = 0; + return Mutex::unlock(); + } + } + else + { + osg::notify(osg::NOTICE)<<"Error: ReentrantMutex::unlock() - unlocking from the wrong thread."<0) + { + --_lockCount; + if (_lockCount<=0) + { + _threadHoldingMutex = 0; + return Mutex::unlock(); + } + } + #endif + return 0; + } + + + virtual int trylock() + { + if (_threadHoldingMutex==OpenThreads::Thread::CurrentThread() && _lockCount>0) + { + OpenThreads::ScopedLock lock(_lockCountMutex); + ++_lockCount; + return 0; + } + else + { + int result = Mutex::trylock(); + if (result==0) + { + OpenThreads::ScopedLock lock(_lockCountMutex); + + _threadHoldingMutex = OpenThreads::Thread::CurrentThread(); + _lockCount = 1; + } + return result; + } + } + + private: + + ReentrantMutex(const ReentrantMutex&):OpenThreads::Mutex() {} + + ReentrantMutex& operator =(const ReentrantMutex&) { return *(this); } + + OpenThreads::Thread* _threadHoldingMutex; + + OpenThreads::Mutex _lockCountMutex; + unsigned int _lockCount; + +}; + +} + +#endif diff --git a/include/OpenThreads/ScopedLock b/include/OpenThreads/ScopedLock new file mode 100644 index 000000000..fe84efa40 --- /dev/null +++ b/include/OpenThreads/ScopedLock @@ -0,0 +1,47 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// ScopedLock and ReverseScopedLock templates +// ~~~~~~~ +// +#ifndef _ScopedLock_ +#define _ScopedLock_ + +namespace OpenThreads{ + +template class ScopedLock +{ + private: + M& m_lock; + ScopedLock(const ScopedLock&); // prevent copy + ScopedLock& operator=(const ScopedLock&); // prevent assign + public: + explicit ScopedLock(M& m):m_lock(m) {m_lock.lock();} + ~ScopedLock(){m_lock.unlock();} +}; + +template class ReverseScopedLock +{ + private: + M& m_lock; + ReverseScopedLock(const ReverseScopedLock&); // prevent copy + ReverseScopedLock& operator=(const ReverseScopedLock&); // prevent assign + public: + explicit ReverseScopedLock(M& m):m_lock(m) {m_lock.unlock();} + ~ReverseScopedLock(){m_lock.lock();} +}; + +} +#endif diff --git a/include/OpenThreads/Thread b/include/OpenThreads/Thread new file mode 100644 index 000000000..0297b9876 --- /dev/null +++ b/include/OpenThreads/Thread @@ -0,0 +1,389 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Thread - C++ Thread class +// ~~~~~~~~ +// + +#ifndef _OPENTHREADS_THREAD_ +#define _OPENTHREADS_THREAD_ + +#include + +#include + +namespace OpenThreads { + +/** + * Get the number of processors. + * + * Note, systems where no support exists for querrying the number of processors, 1 is returned. + * + */ +extern OPENTHREAD_EXPORT_DIRECTIVE int GetNumberOfProcessors(); + +/** + * Set the processor affinity of current thread. + * + * Note, systems where no support exists no affinity will be set, and -1 will be returned. + * + */ +extern OPENTHREAD_EXPORT_DIRECTIVE int SetProcessorAffinityOfCurrentThread(unsigned int cpunum); + +/** + * @class Thread + * @brief This class provides an object-oriented thread interface. + */ +class OPENTHREAD_EXPORT_DIRECTIVE Thread { + +public: + + /** + * Set the concurrency level for a running application. This method + * only has effect if the pthreads thread model is being used, and + * then only when that model is many-to-one (eg. irix). + * in other cases it is ignored. The concurrency level is only a + * *hint* as to the number of execution vehicles to use, the actual + * implementation may do anything it wants. Setting the value + * to 0 returns things to their default state. + * + * @return previous concurrency level, -1 indicates no-op. + */ + static int SetConcurrency(int concurrencyLevel); + + /** + * Get the concurrency level for a running application. In this + * case, a return code of 0 means that the application is in default + * mode. A return code of -1 means that the application is incapable + * of setting an arbitrary concurrency, because it is a one-to-one + * execution model (sprocs, linuxThreads) + */ + static int GetConcurrency(); + + /** + * Enumerated Type for thread priority + */ + enum ThreadPriority { + + THREAD_PRIORITY_MAX, /**< The maximum possible priority */ + THREAD_PRIORITY_HIGH, /**< A high (but not max) setting */ + THREAD_PRIORITY_NOMINAL, /**< An average priority */ + THREAD_PRIORITY_LOW, /**< A low (but not min) setting */ + THREAD_PRIORITY_MIN, /**< The miniumum possible priority */ + THREAD_PRIORITY_DEFAULT /**< Priority scheduling default */ + + }; + + /** + * Enumerated Type for thread scheduling policy + */ + enum ThreadPolicy { + + THREAD_SCHEDULE_FIFO, /**< First in, First out scheduling */ + THREAD_SCHEDULE_ROUND_ROBIN, /**< Round-robin scheduling (LINUX_DEFAULT) */ + THREAD_SCHEDULE_TIME_SHARE, /**< Time-share scheduling (IRIX DEFAULT) */ + THREAD_SCHEDULE_DEFAULT /**< Default scheduling */ + + }; + + /** + * Constructor + */ + Thread(); + + /** + * Destructor + */ + virtual ~Thread(); + + + /** + * Return a pointer to the current running thread + */ + static Thread *CurrentThread(); + + + /** + * Initialize Threading in a program. This method must be called before + * you can do any threading in a program. + */ + static void Init(); + + /** + * Yield the processor. + * + * @note This method operates on the calling process. And is + * equivalent to calling sched_yield(). + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + static int YieldCurrentThread(); + + /** + * This method will return the ThreadPriority of the master process. + * (ie, the one calling the thread->start() methods for the first time) + * The method will almost certainly return + * Thread::THREAD_PRIORITY_DEFAULT if + * Init() has not been called. + * + * @return the Thread::ThreadPriority of the master thread. + */ + static ThreadPriority GetMasterPriority() {return s_masterThreadPriority;}; + + + /** + * Get a unique thread id. This id is monotonically increasing. + * + * @return a unique thread identifier + */ + int getThreadId(); + + /** + * Get the thread's process id. This is the pthread_t or pid_t value + * depending on the threading model being used. + * + * @return thread process id. + */ + size_t getProcessId(); + + /** + * Start the thread. This method will configure the thread, set + * it's priority, and spawn it. + * + * @note if the stack size specified setStackSize is smaller than the + * smallest allowable stack size, the threads stack size will be set to + * the minimum allowed, and may be retrieved via the getStackSize() + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int start(); + int startThread(); + + /** + * Test the cancel state of the thread. If the thread has been canceled + * this method will cause the thread to exit now. This method operates + * on the calling thread. + * + * Returns 0 if normal, -1 if called from a thread other that this. + */ + int testCancel(); + + + /** + * Cancel the thread. Equivalent to SIGKILL. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + virtual int cancel(); + + /** + * Set the thread's schedule priority. This is a complex method. + * Beware of thread priorities when using a many-to-many kernel + * entity implemenation (such as IRIX pthreads). If one is not carefull + * to manage the thread priorities, a priority inversion deadlock can + * easily occur (Although the OpenThreads::Mutex & OpenThreads::Barrier + * constructs have been designed with this senario in mind). Unless + * you have explicit need to set the schedule pirorites for a given + * task, it is best to leave them alone. + * + * @note some implementations (notably LinuxThreads and IRIX Sprocs) + * only alow you to decrease thread priorities dynamically. Thus, + * a lower priority thread will not allow it's priority to be raised + * on the fly. + * + * @note seting the environment variable OUTPUT_THREADLIB_SCHEDULING_INFO + * will output scheduling information for each thread to stdout. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setSchedulePriority(ThreadPriority priority); + + /** + * Get the thread's schedule priority (if able) + * + * @note seting the environment variable OUTPUT_THREADLIB_SCHEDULING_INFO + * will output scheduling information for each thread to stdout. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int getSchedulePriority(); + + /** + * Set the thread's scheduling policy (if able) + * + * @note On some implementations (notably IRIX Sprocs & LinuxThreads) + * The policy may prohibit the use of SCHEDULE_ROUND_ROBIN and + * SCHEDULE_FIFO policies - due to their real-time nature, and + * the danger of deadlocking the machine when used as super-user. + * In such cases, the command is a no-op. + * + * @note seting the environment variable OUTPUT_THREADLIB_SCHEDULING_INFO + * will output scheduling information for each thread to stdout. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setSchedulePolicy(ThreadPolicy policy); + + /** + * Get the thread's policy (if able) + * + * @note seting the environment variable OUTPUT_THREADLIB_SCHEDULING_INFO + * will output scheduling information for each thread to stdout. + * + * @return policy if normal, -1 if errno set, errno code otherwise. + */ + int getSchedulePolicy(); + + /** + * Set the thread's desired stack size (in bytes). + * This method is an attribute of the thread and must be called + * *before* the start() method is invoked. + * + * @note a return code of 13 (EACESS) means that the thread stack + * size can no longer be changed. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setStackSize(size_t size); + + /** + * Get the thread's desired stack size. + * + * @return the thread's stack size. 0 indicates that the stack size + * has either not yet been initialized, or not yet been specified by + * the application. + */ + size_t getStackSize(); + + /** + * Print the thread's scheduling information to stdout. + */ + void printSchedulingInfo(); + + /** + * Detach the thread from the calling process. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int detach(); + + /** + * Join the calling process with the thread + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int join(); + + /** + * Disable thread cancelation altogether. Thread::cancel() has no effect. + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setCancelModeDisable(); + + /** + * Mark the thread to cancel aysncronously on Thread::cancel(). + * (May not be available with process-level implementations). + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setCancelModeAsynchronous(); + + /** + * Mark the thread to cancel at the earliest convenience on + * Thread::cancel() (This is the default) + * + * @return 0 if normal, -1 if errno set, errno code otherwise. + */ + int setCancelModeDeferred(); + + /** + * Query the thread's running status + * + * @return true if running, false if not. + */ + bool isRunning(); + + /** + * Thread's run method. Must be implemented by derived classes. + * This is where the action happens. + */ + virtual void run() = 0; + + /** + * Thread's cancel cleanup routine, called upon cancel(), after the + * cancelation has taken place, but before the thread exits completely. + * This method should be used to repair parts of the thread's data + * that may have been damaged by a pre-mature cancel. No-op by default. + */ + virtual void cancelCleanup() {}; + + void* getImplementation(){ return _prvData; }; + + /** Thread's processor affinity method. This binds a thread to a + * processor whenever possible. This call must be made before + * start() or startThread() and has no effect after the thread + * has been running. In the pthreads implementation, this is only + * implemented on sgi, through a pthread extension. On other pthread + * platforms this is ignored. Returns 0 on success, implementation's + * error on failure, or -1 if ignored. + */ + int setProcessorAffinity( unsigned int cpunum ); + + /** microSleep method, equivilant to the posix usleep(microsec). + * This is not strictly thread API but is used + * so often with threads. It's basically UNIX usleep. Parameter is + * number of microseconds we current thread to sleep. Returns 0 on + * succes, non-zero on failure (UNIX errno or GetLastError() will give + * detailed description. + */ + static int microSleep( unsigned int microsec); + +private: + + /** + * The Private Actions class is allowed to operate on private data. + */ + friend class ThreadPrivateActions; + + /** + * Private copy constructor, to prevent tampering. + */ + Thread(const Thread &/*t*/) {}; + + /** + * Private copy assignment, to prevent tampering. + */ + Thread &operator=(const Thread &/*t*/) {return *(this);}; + + /** + * Implementation-specific data + */ + void * _prvData; + + /** + * Master thread's priority, set by Thread::Init. + */ + static ThreadPriority s_masterThreadPriority; + + /** + * Is initialized flag + */ + static bool s_isInitialized; +}; + +} + +#endif // !_OPENTHREADS_THREAD_ diff --git a/include/OpenThreads/Version b/include/OpenThreads/Version new file mode 100644 index 000000000..12ba08a24 --- /dev/null +++ b/include/OpenThreads/Version @@ -0,0 +1,38 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OPENTHREADS_VERSION +#define OPENTHREADS_VERSION 1 + +#include + +extern "C" { + +#define OPENTHREADS_MAJOR_VERSION 2 +#define OPENTHREADS_MINOR_VERSION 2 +#define OPENTHREADS_PATCH_VERSION 0 +#define OPENTHREADS_SOVERSION 9 + +/** OpenThreadsGetVersion() returns the library version number. + * Numbering convention : OpenThreads-1.0 will return 1.0 from OpenThreadsGetVersion. */ +extern OPENTHREAD_EXPORT_DIRECTIVE const char* OpenThreadsGetVersion(); + +/** The OpenThreadsGetSOVersion() method returns the OpenSceneGraph soversion number. */ +extern OPENTHREAD_EXPORT_DIRECTIVE const char* OpenThreadsGetSOVersion(); + +/** The OpenThreadsGetLibraryName() method returns the library name in human-friendly form. */ +extern OPENTHREAD_EXPORT_DIRECTIVE const char* OpenThreadsGetLibraryName(); + +} + +#endif diff --git a/src/OpenThreads/CMakeLists.txt b/src/OpenThreads/CMakeLists.txt new file mode 100644 index 000000000..00a321ac1 --- /dev/null +++ b/src/OpenThreads/CMakeLists.txt @@ -0,0 +1,72 @@ +# This is mainly for Windows declspec, but other platforms know +# what to do with it. +ADD_DEFINITIONS(-DOPENTHREADS_EXPORTS) + +SET(OPENTHREADS_MAJOR_VERSION 2) +SET(OPENTHREADS_MINOR_VERSION 2) +SET(OPENTHREADS_PATCH_VERSION 0) +SET(OPENTHREADS_SOVERSION 9) + +SET(OPENTHREADS_VERSION ${OPENTHREADS_MAJOR_VERSION}.${OPENTHREADS_MINOR_VERSION}.${OPENTHREADS_PATCH_VERSION}) + +SET(HEADER_PATH ${OpenThreads_SOURCE_DIR}/include/OpenThreads) +SET(OpenThreads_PUBLIC_HEADERS + ${HEADER_PATH}/Barrier + ${HEADER_PATH}/Block + ${HEADER_PATH}/Condition + ${HEADER_PATH}/Exports + ${HEADER_PATH}/Mutex + ${HEADER_PATH}/ReadWriteMutex + ${HEADER_PATH}/ReentrantMutex + ${HEADER_PATH}/ScopedLock + ${HEADER_PATH}/Thread + ${HEADER_PATH}/Version +) + +# User Options +OPTION(DYNAMIC_OPENTHREADS "Set to ON to build OpenThreads for dynamic linking. Use OFF for static." ON) +IF (DYNAMIC_OPENTHREADS) + SET(OPENTHREADS_USER_DEFINED_DYNAMIC_OR_STATIC "SHARED") +ELSE (DYNAMIC_OPENTHREADS) + SET(OPENTHREADS_USER_DEFINED_DYNAMIC_OR_STATIC "STATIC") +ENDIF(DYNAMIC_OPENTHREADS) + +# Use our modified version of FindThreads.cmake which has Sproc hacks. +FIND_PACKAGE(Threads) + +# Do we have sproc? +IF(CMAKE_SYSTEM MATCHES IRIX) + IF(CMAKE_USE_SPROC_INIT) + # In this case, only Sproc exists, so no option. + SET(OPENTHREADS_USE_SPROC_INSTEAD_OF_PTHREADS 1) + ELSE(CMAKE_USE_SPROC_INIT) + IF(CMAKE_HAVE_SPROC_H) + OPTION(OPENTHREADS_USE_SPROC_INSTEAD_OF_PTHREADS "Set to ON to build OpenThreads against sproc instead of pthreads" OFF) + ENDIF(CMAKE_HAVE_SPROC_H) + ENDIF(CMAKE_USE_SPROC_INIT) +ENDIF(CMAKE_SYSTEM MATCHES IRIX) + +# Maybe we should be using the FindThreads.cmake module? +IF(WIN32) + # So I think Cygwin wants to use pthreads + IF(CYGWIN) + SUBDIRS(pthreads) + ELSE(CYGWIN) + # Everybody else including Msys should probably go here + SUBDIRS(win32) + # examples) + ENDIF(CYGWIN) +ELSE(WIN32) + IF(UNIX) + IF(OPENTHREADS_USE_SPROC_INSTEAD_OF_PTHREADS) + SUBDIRS(sproc) + ELSE(OPENTHREADS_USE_SPROC_INSTEAD_OF_PTHREADS) + SUBDIRS(pthreads) + ENDIF(OPENTHREADS_USE_SPROC_INSTEAD_OF_PTHREADS) + ELSE(UNIX) + MESSAGE("Sorry, OpenThreads may not support your platform") + ENDIF(UNIX) +ENDIF(WIN32) + + + diff --git a/src/OpenThreads/common/Version.cpp b/src/OpenThreads/common/Version.cpp new file mode 100644 index 000000000..e2e71ea98 --- /dev/null +++ b/src/OpenThreads/common/Version.cpp @@ -0,0 +1,57 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#include +#include +#include + + +/* These functions expect OPENTHREADS_MAJOR_VERSION, + * OPENTHREADS_MINOR_VERSION, OPENTHREADS_PATCH_VERSION, and + * OPENTHREADS_SOVERSION to be defined by the build system. +*/ + +extern "C" { + +const char* OpenThreadsGetVersion() +{ + static char OpenThreads_version[256]; + static int OpenThreads_version_init = 1; + if (OpenThreads_version_init) + { + sprintf(OpenThreads_version,"%d.%d.%d",OPENTHREADS_MAJOR_VERSION,OPENTHREADS_MINOR_VERSION,OPENTHREADS_PATCH_VERSION); + OpenThreads_version_init = 0; + } + + return OpenThreads_version; +} + +const char* OpenThreadsGetSOVersion() +{ + static char OpenThreads_soversion[32]; + static int OpenThreads_soversion_init = 1; + if (OpenThreads_soversion_init) + { + sprintf(OpenThreads_soversion,"%d",OPENTHREADS_SOVERSION); + OpenThreads_soversion_init = 0; + } + + return OpenThreads_soversion; +} + +const char* OpenThreadsGetLibraryName() +{ + return "OpenThreads Library"; +} + +} diff --git a/src/OpenThreads/pthreads/CMakeLists.txt b/src/OpenThreads/pthreads/CMakeLists.txt new file mode 100644 index 000000000..a1e9decb8 --- /dev/null +++ b/src/OpenThreads/pthreads/CMakeLists.txt @@ -0,0 +1,116 @@ +# This file should only be included when using Pthreads + +INCLUDE (CheckFunctionExists) +INCLUDE (CheckLibraryExists) +INCLUDE (CheckSymbolExists) +INCLUDE (CheckCXXSourceCompiles) + +SET(LIB_NAME OpenThreads) +SET(LIB_PUBLIC_HEADERS ${OpenThreads_PUBLIC_HEADERS}) + +ADD_LIBRARY(${LIB_NAME} + ${OPENTHREADS_USER_DEFINED_DYNAMIC_OR_STATIC} + ${LIB_PUBLIC_HEADERS} + PThread.c++ + PThreadBarrier.c++ + PThreadBarrierPrivateData.h + PThreadCondition.c++ + PThreadConditionPrivateData.h + PThreadMutex.c++ + PThreadMutexPrivateData.h + PThreadPrivateData.h + ../common/Version.cpp +) + +IF(OPENTHREADS_SONAMES) + SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION ${OPENTHREADS_VERSION} SOVERSION ${OPENTHREADS_SOVERSION}) +ENDIF(OPENTHREADS_SONAMES) + +SET(CMAKE_REQUIRED_LIBRARIES_SAFE "${CMAKE_REQUIRED_LIBRARIES}") +SET(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}") + +CHECK_FUNCTION_EXISTS(pthread_yield HAVE_PTHREAD_YIELD) +IF(HAVE_PTHREAD_YIELD) + ADD_DEFINITIONS(-DHAVE_PTHREAD_YIELD) +ELSE(HAVE_PTHREAD_YIELD) + # sched_yield appears not in libc, pthreads or whatever on some systems + CHECK_FUNCTION_EXISTS(sched_yield HAVE_SCHED_YIELD) + IF(NOT HAVE_SCHED_YIELD) + CHECK_LIBRARY_EXISTS(rt sched_yield "" HAVE_SCHED_YIELD) + IF(HAVE_SCHED_YIELD) + SET(CMAKE_THREAD_LIBS_INIT "${CMAKE_THREAD_LIBS_INIT} -lrt") + ENDIF(HAVE_SCHED_YIELD) + ENDIF(NOT HAVE_SCHED_YIELD) + IF(HAVE_SCHED_YIELD) + ADD_DEFINITIONS(-DHAVE_SCHED_YIELD) + ENDIF(HAVE_SCHED_YIELD) +ENDIF(HAVE_PTHREAD_YIELD) + +IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # need to have that for pthread_setaffinity_np on linux + ADD_DEFINITIONS(-D_GNU_SOURCE) + SET(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_GNU_SOURCE") +ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + +CHECK_FUNCTION_EXISTS(pthread_setconcurrency HAVE_PTHREAD_SETCONCURRENCY) +IF(HAVE_PTHREAD_SETCONCURRENCY) + ADD_DEFINITIONS(-DHAVE_PTHREAD_SETCONCURRENCY) +ENDIF(HAVE_PTHREAD_SETCONCURRENCY) + +CHECK_FUNCTION_EXISTS(pthread_getconcurrency HAVE_PTHREAD_GETCONCURRENCY) +IF(HAVE_PTHREAD_GETCONCURRENCY) + ADD_DEFINITIONS(-DHAVE_PTHREAD_GETCONCURRENCY) +ENDIF(HAVE_PTHREAD_GETCONCURRENCY) + +CHECK_FUNCTION_EXISTS(pthread_setaffinity_np HAVE_PTHREAD_SETAFFINITY_NP) +IF(HAVE_PTHREAD_SETAFFINITY_NP) + ADD_DEFINITIONS(-DHAVE_PTHREAD_SETAFFINITY_NP) +ELSE(HAVE_PTHREAD_SETAFFINITY_NP) + CHECK_CXX_SOURCE_COMPILES(" +#include +int main() { + cpu_set_t cpumask; + sched_setaffinity( 0, sizeof(cpumask), &cpumask ); + return 0; +}" HAVE_THREE_PARAM_SCHED_SETAFFINITY) + IF(HAVE_THREE_PARAM_SCHED_SETAFFINITY) + ADD_DEFINITIONS(-DHAVE_THREE_PARAM_SCHED_SETAFFINITY) + ELSE(HAVE_THREE_PARAM_SCHED_SETAFFINITY) + CHECK_CXX_SOURCE_COMPILES(" +#include +int main() { + cpu_set_t cpumask; + sched_setaffinity( 0, &cpumask ); + return 0; +}" HAVE_TWO_PARAM_SCHED_SETAFFINITY) + IF(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + ADD_DEFINITIONS(-DHAVE_TWO_PARAM_SCHED_SETAFFINITY) + ENDIF(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + ENDIF(HAVE_THREE_PARAM_SCHED_SETAFFINITY) +ENDIF(HAVE_PTHREAD_SETAFFINITY_NP) + +SET(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_SAFE}") + +TARGET_LINK_LIBRARIES(${LIB_NAME} + ${CMAKE_THREAD_LIBS_INIT} +) + +# Since we're building different platforms binaries in +# their respective directories, we need to set the +# link directory so it can find this location. +LINK_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} +) + +INSTALL( + TARGETS OpenThreads + ARCHIVE DESTINATION lib${LIB_POSTFIX} + LIBRARY DESTINATION lib${LIB_POSTFIX} + RUNTIME DESTINATION bin +) +INSTALL( + FILES ${OpenThreads_PUBLIC_HEADERS} + DESTINATION include/OpenThreads +) + +#commented out# INCLUDE(ModuleInstall OPTIONAL) diff --git a/src/OpenThreads/pthreads/GNUmakefile b/src/OpenThreads/pthreads/GNUmakefile new file mode 100644 index 000000000..a800725fd --- /dev/null +++ b/src/OpenThreads/pthreads/GNUmakefile @@ -0,0 +1,46 @@ +TOPDIR = ../. +include $(TOPDIR)/Make/makedefs + +C++FILES = \ + PThread.c++ \ + PThreadMutex.c++ \ + PThreadCondition.c++ \ + PThreadBarrier.c++ \ + $(NULL) + +INC += -I$(TOPDIR)/include -I. + +ifeq ($(OS),Linux) +DEF += -fPIC -DLinux -DGL_GLEXT_PROTOTYPES +LIBS += -lpthread +endif + +ifeq ($(OS),SunOS) +LIBS += -lpthread -lposix4 +endif + +ifeq ($(OS),IRIX) +LIBS += -lpthread +endif + +ifeq ($(OS),Darwin) +LIBS += -lpthread +endif + +ifeq ($(OS),CYGWIN) +LIBS += -lpthread +DEF += -DOPENTHREADS_EXPORTS +endif + +ifeq ($(OS),MINGW) +LIBS += -lpthread -lwinmm +DEF += -DOPENTHREADS_EXPORTS +endif + +TARGET_BASENAME = OpenThreads +LIB = $(LIB_PREFIX)$(TARGET_BASENAME) + +ifeq ($(COMPILE_USING_TWO_PARAM_sched_setaffinity),yes) +DEF += -DCOMPILE_USING_TWO_PARAM_sched_setaffinity +endif +include $(TOPDIR)/Make/makerules diff --git a/src/OpenThreads/pthreads/PThread.c++ b/src/OpenThreads/pthreads/PThread.c++ new file mode 100644 index 000000000..07c99730e --- /dev/null +++ b/src/OpenThreads/pthreads/PThread.c++ @@ -0,0 +1,992 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThread.c++ - C++ Thread class built on top of posix threads. +// ~~~~~~~~~~~ + +#include +#include +#include +#include +#include + +#if defined __linux || defined __sun || defined __APPLE__ +#include +#include +#include +#include +#endif +#if defined(__sgi) +#include +#endif +#if defined(__hpux) +#include +#endif + +#if defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) +# include +#endif +#if defined (__FreeBSD__) || defined (__APPLE__) || defined (__MACH__) + #include + #include +#endif + +#include +#include "PThreadPrivateData.h" + +#include + +using namespace OpenThreads; + +extern int errno; +const char *OPENTHREAD_VERSION_STRING = "OpenThreads v1.2preAlpha, Posix Threads (Public Implementation)"; + +#ifdef DEBUG +# define DPRINTF(arg) printf arg +#else +# define DPRINTF(arg) +#endif + +//----------------------------------------------------------------------------- +// Initialize the static unique ids. +// +int PThreadPrivateData::nextId = 0; + +//----------------------------------------------------------------------------- +// Initialize thread master priority level +// +Thread::ThreadPriority Thread::s_masterThreadPriority = + Thread::THREAD_PRIORITY_DEFAULT; + +bool Thread::s_isInitialized = false; +pthread_key_t PThreadPrivateData::s_tls_key; + +struct ThreadCleanupStruct { + + OpenThreads::Thread *thread; + volatile bool *runflag; + +}; + +//----------------------------------------------------------------------------- +// This cleanup handler is necessary to ensure that the thread will cleanup +// and set its isRunning flag properly. +// +void thread_cleanup_handler(void *arg) { + + ThreadCleanupStruct *tcs = static_cast(arg); + + tcs->thread->cancelCleanup(); + *(tcs->runflag) = false; + +} + +//----------------------------------------------------------------------------- +// Class to support some static methods necessary for pthread's to work +// correctly. +// + +namespace OpenThreads { + +class ThreadPrivateActions { + + //------------------------------------------------------------------------- + // We're friendly to Thread, so it can issue the methods. + // + friend class Thread; + +private: + + //------------------------------------------------------------------------- + // pthreads standard start routine. + // + static void *StartThread(void *data) { + + Thread *thread = static_cast(data); + + PThreadPrivateData *pd = + static_cast(thread->_prvData); + + + if (pd->cpunum>=0) + { +#if defined(__sgi) + pthread_setrunon_np( pd->cpunum ); +#elif defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + cpu_set_t cpumask; + CPU_ZERO( &cpumask ); + CPU_SET( pd->cpunum, &cpumask ); + +#if defined(HAVE_PTHREAD_SETAFFINITY_NP) + pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); +#elif defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, sizeof(cpumask), &cpumask ); +#elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, &cpumask ); +#endif +#endif + } + + + ThreadCleanupStruct tcs; + tcs.thread = thread; + tcs.runflag = &pd->isRunning; + + // Set local storage so that Thread::CurrentThread() can return the right thing + int status = pthread_setspecific(PThreadPrivateData::s_tls_key, thread); + if (status) + { + printf("Error: pthread_setspecific(,) returned error status, status = %d\n",status); + } + + pthread_cleanup_push(thread_cleanup_handler, &tcs); + +#ifdef ALLOW_PRIORITY_SCHEDULING + + //--------------------------------------------------------------------- + // Set the proper scheduling priorities + // + SetThreadSchedulingParams(thread); + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + pd->isRunning = true; + + // release the thread that created this thread. + pd->threadStartedBlock.release(); + + thread->run(); + + pd->isRunning = false; + + pthread_cleanup_pop(0); + + return 0; + + }; + + //------------------------------------------------------------------------- + // Print information related to thread schduling parameters. + // + static void PrintThreadSchedulingInfo(Thread *thread) { + +#ifdef ALLOW_PRIORITY_SCHEDULING // [ + + if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) { + + int status, my_policy, min_priority, max_priority; + struct sched_param my_param; + + status = pthread_getschedparam(thread->getProcessId(), + &my_policy, + &my_param); + + if(status != 0) { + printf("THREAD INFO (%d) : Get sched: %s\n", + thread->getProcessId(), + strerror(status)); + } else { + printf( + "THREAD INFO (%d) : Thread running at %s / Priority: %d\n", + thread->getProcessId(), + (my_policy == SCHED_FIFO ? "SCHEDULE_FIFO" + : (my_policy == SCHED_RR ? "SCHEDULE_ROUND_ROBIN" + : (my_policy == SCHED_OTHER ? "SCHEDULE_OTHER" + : "UNKNOWN"))), + my_param.sched_priority); + + max_priority = sched_get_priority_max(my_policy); + min_priority = sched_get_priority_min(my_policy); + + printf( + "THREAD INFO (%d) : Max priority: %d, Min priority: %d\n", + thread->getProcessId(), + max_priority, min_priority); + + } + + } else { + printf( + "THREAD INFO (%d) POSIX Priority scheduling not available\n", + thread->getProcessId()); + } + + fflush(stdout); + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + } + + //-------------------------------------------------------------------------- + // Set thread scheduling parameters. Unfortunately on Linux, there's no + // good way to set this, as pthread_setschedparam is mostly a no-op. + // + static int SetThreadSchedulingParams(Thread *thread) { + + int status = 0; + +#ifdef ALLOW_PRIORITY_SCHEDULING // [ + + if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) { + + int th_policy; + int max_priority, nominal_priority, min_priority; + sched_param th_param; + pthread_getschedparam(thread->getProcessId(), + &th_policy, &th_param); + +#ifndef __linux__ + + switch(thread->getSchedulePolicy()) { + + case Thread::THREAD_SCHEDULE_FIFO: + th_policy = SCHED_FIFO; + break; + + case Thread::THREAD_SCHEDULE_ROUND_ROBIN: + th_policy = SCHED_RR; + break; + + case Thread::THREAD_SCHEDULE_TIME_SHARE: + th_policy = SCHED_OTHER; + break; + + default: +#ifdef __sgi + th_policy = SCHED_RR; +#else + th_policy = SCHED_FIFO; +#endif + break; + }; + +#else + th_policy = SCHED_OTHER; // Must protect linux from realtime. +#endif + +#ifdef __linux__ + + max_priority = 0; + min_priority = 20; + nominal_priority = (max_priority + min_priority)/2; + +#else + + max_priority = sched_get_priority_max(th_policy); + min_priority = sched_get_priority_min(th_policy); + nominal_priority = (max_priority + min_priority)/2; + +#endif + + switch(thread->getSchedulePriority()) { + + case Thread::THREAD_PRIORITY_MAX: + th_param.sched_priority = max_priority; + break; + + case Thread::THREAD_PRIORITY_HIGH: + th_param.sched_priority = (max_priority + nominal_priority)/2; + break; + + case Thread::THREAD_PRIORITY_NOMINAL: + th_param.sched_priority = nominal_priority; + break; + + case Thread::THREAD_PRIORITY_LOW: + th_param.sched_priority = (min_priority + nominal_priority)/2; + break; + + case Thread::THREAD_PRIORITY_MIN: + th_param.sched_priority = min_priority; + break; + + default: + th_param.sched_priority = max_priority; + break; + + } + + status = pthread_setschedparam(thread->getProcessId(), + th_policy, + &th_param); + + + if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0) + PrintThreadSchedulingInfo(thread); + + } + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + return status; + }; +}; + +} + +//---------------------------------------------------------------------------- +// +// Description: Set the concurrency level (no-op) +// +// Use static public +// +int Thread::SetConcurrency(int concurrencyLevel) { + +#if defined (HAVE_PTHREAD_SETCONCURRENCY) + return pthread_setconcurrency(concurrencyLevel); +#else + return -1; +#endif + +} + +//---------------------------------------------------------------------------- +// +// Description: Get the concurrency level +// +// Use static public +// +int Thread::GetConcurrency() { + +#if defined (HAVE_PTHREAD_GETCONCURRENCY) + return pthread_getconcurrency(); +#else + return -1; +#endif + +} + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Thread::Thread() { + + if(!s_isInitialized) Init(); + + PThreadPrivateData *pd = new PThreadPrivateData(); + pd->stackSize = 0; + pd->stackSizeLocked = false; + pd->idSet = false; + pd->isRunning = false; + pd->isCanceled = false; + pd->uniqueId = pd->nextId; + pd->nextId++; + pd->threadPriority = Thread::THREAD_PRIORITY_DEFAULT; + pd->threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT; + pd->cpunum = -1; + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Thread::~Thread() +{ + PThreadPrivateData *pd = static_cast(_prvData); + + if(pd->isRunning) + { + std::cout<<"Error: Thread "<(pthread_getspecific(PThreadPrivateData::s_tls_key)); + + return thread; + +} + +//----------------------------------------------------------------------------- +// +// Description: Initialize Threading +// +// Use: public. +// +void Thread::Init() { + + if(s_isInitialized) return; + + // Allocate a key to be used to access thread local storage + int status = pthread_key_create(&PThreadPrivateData::s_tls_key, NULL); + if (status) + { + printf("Error: pthread_key_create(,) returned error status, status = %d\n",status); + } + +#ifdef ALLOW_PRIORITY_SCHEDULING + + //-------------------------------------------------------------------------- + // If we've got priority scheduling, set things to nominal. + // + if(sysconf(_POSIX_THREAD_PRIORITY_SCHEDULING)) { + + int max_priority, nominal_priority, min_priority; + + int th_policy; + sched_param th_param; + pthread_getschedparam(pthread_self(), + &th_policy, &th_param); + + max_priority = sched_get_priority_max(th_policy); + min_priority = sched_get_priority_min(th_policy); + nominal_priority = (max_priority + min_priority)/2; + + th_param.sched_priority = nominal_priority; + + pthread_setschedparam(pthread_self(), + th_policy, + &th_param); + + s_masterThreadPriority = Thread::THREAD_PRIORITY_NOMINAL; + + } else { + + s_masterThreadPriority = Thread::THREAD_PRIORITY_DEFAULT; + + } + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + s_isInitialized = true; + +} + +//----------------------------------------------------------------------------- +// +// Description: Get a unique identifier for this thread. +// +// Use: public +// +int Thread::getThreadId() { + + PThreadPrivateData *pd = static_cast (_prvData); + return pd->uniqueId; +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's process id +// +// Use: public +// +size_t Thread::getProcessId() { + + PThreadPrivateData *pd = static_cast (_prvData); + + if(pd->idSet == false) return (size_t)(pthread_self()); + + return (size_t)(pd->tid); +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's processor affinity +// +// Use: public +// +int Thread::setProcessorAffinity(unsigned int cpunum) +{ + PThreadPrivateData *pd = static_cast (_prvData); + pd->cpunum = cpunum; + if (pd->cpunum<0) return -1; + +#ifdef __sgi + + int status; + pthread_attr_t thread_attr; + + status = pthread_attr_init( &thread_attr ); + if(status != 0) { + return status; + } + + status = pthread_attr_setscope( &thread_attr, PTHREAD_SCOPE_BOUND_NP ); + return status; + +#elif defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + + if (pd->isRunning && Thread::CurrentThread()==this) + { + cpu_set_t cpumask; + CPU_ZERO( &cpumask ); + CPU_SET( pd->cpunum, &cpumask ); +#if defined(HAVE_PTHREAD_SETAFFINITY_NP) + pthread_setaffinity_np (pthread_self(), sizeof(cpumask), &cpumask); +#elif defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, sizeof(cpumask), &cpumask ); +#elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, &cpumask ); +#endif + } + + return -1; +#else + return -1; +#endif + +} + +//----------------------------------------------------------------------------- +// +// Description: Determine if the thread is running +// +// Use: public +// +bool Thread::isRunning() { + + PThreadPrivateData *pd = static_cast (_prvData); + return pd->isRunning; + +} + +//----------------------------------------------------------------------------- +// +// Description: Start the thread. +// +// Use: public +// +int Thread::start() { + + int status; + pthread_attr_t thread_attr; + + status = pthread_attr_init( &thread_attr ); + if(status != 0) { + return status; + } + + PThreadPrivateData *pd = static_cast (_prvData); + + size_t defaultStackSize; + pthread_attr_getstacksize( &thread_attr, &defaultStackSize); + if(status != 0) { + return status; + } + + if(defaultStackSize < pd->stackSize) { + + pthread_attr_setstacksize( &thread_attr, pd->stackSize); + if(status != 0) { + return status; + } + } + + //------------------------------------------------------------------------- + // Now get what we actually have... + // + pthread_attr_getstacksize( &thread_attr, &defaultStackSize); + if(status != 0) { + return status; + } + + pd->stackSize = defaultStackSize; + + //------------------------------------------------------------------------- + // Prohibit the stack size from being changed. + // + pd->stackSizeLocked = true; + +#ifdef ALLOW_PRIORITY_SCHEDULING + + status = pthread_attr_setinheritsched( &thread_attr, + PTHREAD_EXPLICIT_SCHED ); + + pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM); + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + if(status != 0) { + return status; + } + + pd->threadStartedBlock.reset(); + + status = pthread_create(&(pd->tid), &thread_attr, + ThreadPrivateActions::StartThread, + static_cast(this)); + + // wait till the thread has actually started. + pd->threadStartedBlock.block(); + + if(status != 0) { + return status; + } + + pd->idSet = true; + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Alternate thread start routine. +// +// Use: public +// +int Thread::startThread() +{ + if (_prvData) return start(); + else return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Join the thread. +// +// Use: public +// +int Thread::detach() { + + PThreadPrivateData *pd = static_cast (_prvData); + return pthread_detach(pd->tid); + +} + +//----------------------------------------------------------------------------- +// +// Description: Join the thread. +// +// Use: public +// +int Thread::join() { + + void *threadResult = 0; // Dummy var. + PThreadPrivateData *pd = static_cast (_prvData); + return pthread_join(pd->tid, &threadResult); + +} + +//----------------------------------------------------------------------------- +// +// Description: test the cancel state of the thread. +// +// Use: public +// +int Thread::testCancel() { + + PThreadPrivateData *pd = static_cast (_prvData); + + if(pthread_self() != pd->tid) + return -1; + + pthread_testcancel(); + + return 0; + +} + + +//----------------------------------------------------------------------------- +// +// Description: Cancel the thread. +// +// Use: public +// +int Thread::cancel() { + + PThreadPrivateData *pd = static_cast (_prvData); + if (pd->isRunning) + { + pd->isCanceled = true; + int status = pthread_cancel(pd->tid); + return status; + } + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Disable cancelibility +// +// Use: public +// +int Thread::setCancelModeDisable() { + + return pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, 0 ); + +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel immediately +// +// Use: public +// +int Thread::setCancelModeAsynchronous() { + + int status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0); + if(status != 0) return status; + + return pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0); +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel at the next convienent point. +// +// Use: public +// +int Thread::setCancelModeDeferred() { + + int status = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, 0); + if(status != 0) return status; + + return pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, 0); + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's schedule priority (if able) +// +// Use: public +// +int Thread::setSchedulePriority(ThreadPriority priority) { + +#ifdef ALLOW_PRIORITY_SCHEDULING + + PThreadPrivateData *pd = static_cast (_prvData); + + pd->threadPriority = priority; + + if(pd->isRunning) + return ThreadPrivateActions::SetThreadSchedulingParams(this); + else + return 0; + +#else + return -1; +#endif + +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's schedule priority (if able) +// +// Use: public +// +int Thread::getSchedulePriority() { + + PThreadPrivateData *pd = static_cast (_prvData); + + return pd->threadPriority; + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::setSchedulePolicy(ThreadPolicy policy) { + +#ifdef ALLOW_PRIORITY_SCHEDULING + + PThreadPrivateData *pd = static_cast (_prvData); + + pd->threadPolicy = policy; + + if(pd->isRunning) + return ThreadPrivateActions::SetThreadSchedulingParams(this); + else + return 0; +#else + return -1; +#endif + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::getSchedulePolicy() { + + PThreadPrivateData *pd = static_cast (_prvData); + + return pd->threadPolicy; + +} + + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's desired stack size +// +// Use: public +// +int Thread::setStackSize(size_t stackSize) { + + PThreadPrivateData *pd = static_cast (_prvData); + + if(pd->stackSizeLocked == true) return 13; // EACESS + + pd->stackSize = stackSize; + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's stack size. +// +// Use: public +// +size_t Thread::getStackSize() { + + PThreadPrivateData *pd = static_cast (_prvData); + + return pd->stackSize; + +} + +//----------------------------------------------------------------------------- +// +// Description: Print the thread's scheduling information to stdout. +// +// Use: public +// +void Thread::printSchedulingInfo() { + + ThreadPrivateActions::PrintThreadSchedulingInfo(this); + +} + +//----------------------------------------------------------------------------- +// +// Description: Yield the processor +// +// Use: protected +// +int Thread::YieldCurrentThread() +{ +#if defined(HAVE_PTHREAD_YIELD) + pthread_yield(); + return 0; +#elif defined(HAVE_SCHED_YIELD) + return sched_yield(); +#else + return -1; +#endif +} + +// Description: sleep +// +// Use: public +// +int Thread::microSleep(unsigned int microsec) +{ + return ::usleep(microsec); +} + + + +//----------------------------------------------------------------------------- +// +// Description: Get the number of processors +// +int OpenThreads::GetNumberOfProcessors() +{ +#if defined(__linux__) + long ret = sysconf(_SC_NPROCESSORS_ONLN); + if (ret == -1) + return 0; + return ret; +#elif defined(__sun__) + long ret = sysconf(_SC_NPROCESSORS_ONLN); + if (ret == -1) + return 0; + return ret; +#elif defined(__sgi) + long ret = sysconf(_SC_NPROC_ONLN); + if (ret == -1) + return 0; + return ret; +#elif defined(__hpux) + int ret = mpctl(MPC_GETNUMSPUS, 0, NULL); + if (ret == -1) + return 0; + return ret; +#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__) + uint64_t num_cpus = 0; + size_t num_cpus_length = sizeof(num_cpus); +#if defined(__FreeBSD__) + sysctlbyname("hw.ncpu", &num_cpus, &num_cpus_length, NULL, 0); +#else + sysctlbyname("hw.activecpu", &num_cpus, &num_cpus_length, NULL, 0); +#endif + return num_cpus; +#else + return 1; +#endif +} + +int OpenThreads::SetProcessorAffinityOfCurrentThread(unsigned int cpunum) +{ + if (cpunum<0) return -1; + + Thread::Init(); + + Thread* thread = Thread::CurrentThread(); + if (thread) + { + return thread->setProcessorAffinity(cpunum); + } + else + { +#if defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + cpu_set_t cpumask; + CPU_ZERO( &cpumask ); + CPU_SET( cpunum, &cpumask ); + +#if defined(HAVE_PTHREAD_SETAFFINITY_NP) + pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); +#elif defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, sizeof(cpumask), &cpumask ); +#elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + sched_setaffinity( 0, &cpumask ); +#endif +#endif + } + + return -1; +} diff --git a/src/OpenThreads/pthreads/PThreadBarrier.c++ b/src/OpenThreads/pthreads/PThreadBarrier.c++ new file mode 100644 index 000000000..033ca8716 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadBarrier.c++ @@ -0,0 +1,242 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadBarrier.c++ - C++ Barrier class built on top of POSIX threads. +// ~~~~~~~~~~~~~~~~~~ +// + +#include +#include +#include +#include "PThreadBarrierPrivateData.h" + +using namespace OpenThreads; + +//---------------------------------------------------------------------------- +// This cancel cleanup handler is necessary to ensure that the barrier's +// mutex gets unlocked on cancel. Otherwise deadlocks could occur with +// later joins. +// +void barrier_cleanup_handler(void *arg) { + + pthread_mutex_t *mutex = static_cast(arg); + + pthread_mutex_unlock(mutex); + +} + +//---------------------------------------------------------------------------- +// +// Description: Constructor +// +// Use: public. +// +Barrier::Barrier(int numThreads) { + + PThreadBarrierPrivateData *pd = new PThreadBarrierPrivateData(); + + pd->cnt = 0; + pd->phase = 0; + pd->maxcnt = numThreads; + + _valid = true; + + pthread_mutexattr_t mutex_attr; + pthread_mutexattr_init( &mutex_attr ); + +#ifndef __linux__ // (not available until NPTL) [ + pthread_mutexattr_settype( &mutex_attr, PTHREAD_MUTEX_ERRORCHECK ); +#endif // ] __linux__ + +#ifdef ALLOW_PRIORITY_SCHEDULING // [ + +#ifdef __sun // [ + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_NONE); +#endif // ] __sun + + //------------------------------------------------------------------------- + // Initialization is a bit tricky, since we have to be able to be aware + // that on many-to-many execution vehicle systems, we may run into + // priority inversion deadlocks if a mutex is shared between threads + // of differing priorities. Systems that do this should provide the + // following protocol attributes to prevent deadlocks. Check at runtime. + // + // PRIO_INHERIT causes any thread locking the mutex to temporarily become + // the same priority as the highest thread also blocked on the mutex. + // Although more expensive, this is the prefered method. + // + // PRIO_PROTECT causes any thread locking the mutex to assume the priority + // specified by setprioceiling. pthread_mutex_lock will fail if + // the priority ceiling is lower than the thread's priority. Therefore, + // the priority ceiling must be set to the max priority in order to + // garantee no deadlocks will occur. + // +#if defined (_POSIX_THREAD_PRIO_INHERIT) || defined (_POSIX_THREAD_PRIO_PROTECT) // [ + + if(sysconf(_POSIX_THREAD_PRIO_INHERIT)) { + + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT); + + } else if (sysconf(_POSIX_THREAD_PRIO_PROTECT)) { + + int th_policy; + struct sched_param th_param; + pthread_getschedparam(pthread_self(), &th_policy, &th_param); + + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_PROTECT); + pthread_mutexattr_setprioceiling(&mutex_attr, + sched_get_priority_max(th_policy)); + + } + +#endif // ] Priority sheduling + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + pthread_mutex_init(&(pd->lock), &mutex_attr); + + pthread_cond_init(&(pd->cond), NULL); + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Description: Destructor +// +// Use: public. +// +Barrier::~Barrier() { + + PThreadBarrierPrivateData *pd = + static_cast(_prvData); + + pthread_mutex_destroy(&(pd->lock)); + + pthread_cond_destroy(&(pd->cond)); + + delete pd; + +} + +//---------------------------------------------------------------------------- +// +// Description: Reset the barrier to its original state +// +// Use: public. +// +void Barrier::reset() { + + PThreadBarrierPrivateData *pd = + static_cast(_prvData); + + pd->cnt = 0; + pd->phase = 0; + +} + +//---------------------------------------------------------------------------- +// +// Description: Block until numThreads threads have entered the barrier. +// +// Use: public. +// +void Barrier::block(unsigned int numThreads) { + + PThreadBarrierPrivateData *pd = + static_cast(_prvData); + + if(numThreads != 0) pd->maxcnt = numThreads; + + int my_phase; + + pthread_mutex_lock(&(pd->lock)); + if( _valid ) + { + my_phase = pd->phase; + ++pd->cnt; + + if (pd->cnt == pd->maxcnt) { // I am the last one + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pthread_cond_broadcast(&(pd->cond)); + } + + while (pd->phase == my_phase) { + + pthread_cleanup_push(barrier_cleanup_handler, &(pd->lock)); + + pthread_cond_wait(&(pd->cond), &(pd->lock)); + + pthread_cleanup_pop(0); + } + } + + pthread_mutex_unlock(&(pd->lock)); + +} + +void Barrier::invalidate() +{ + PThreadBarrierPrivateData *pd = + static_cast(_prvData); + pthread_mutex_lock(&(pd->lock)); + _valid = false; + pthread_mutex_unlock(&(pd->lock)); + release(); +} + +//---------------------------------------------------------------------------- +// +// Description: Release the barrier, now. +// +// Use: public. +// +void Barrier::release() { + + PThreadBarrierPrivateData *pd = + static_cast(_prvData); + + int my_phase; + + pthread_mutex_lock(&(pd->lock)); + my_phase = pd->phase; + + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pthread_cond_broadcast(&(pd->cond)); + pthread_mutex_unlock(&(pd->lock)); + +} + +//---------------------------------------------------------------------------- +// +// Description: Return the number of threads currently blocked in the barrier +// +// Use: public +// +int Barrier::numThreadsCurrentlyBlocked() { + + PThreadBarrierPrivateData *pd = static_cast(_prvData); + + + int numBlocked = -1; + pthread_mutex_lock(&(pd->lock)); + numBlocked = pd->cnt; + pthread_mutex_unlock(&(pd->lock)); + + return numBlocked; +} diff --git a/src/OpenThreads/pthreads/PThreadBarrierPrivateData.h b/src/OpenThreads/pthreads/PThreadBarrierPrivateData.h new file mode 100644 index 000000000..235706a25 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadBarrierPrivateData.h @@ -0,0 +1,52 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadBarrierPrivateData.h - private data structure for barrier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// + +#ifndef _PTHREADBARRIERPRIVATEDATA_H_ +#define _PTHREADBARRIERPRIVATEDATA_H_ + +#include +#include + +namespace OpenThreads { + +class PThreadBarrierPrivateData { + + friend class Barrier; + +private: + + PThreadBarrierPrivateData() {}; + + virtual ~PThreadBarrierPrivateData() {}; + + pthread_cond_t cond; // cv for waiters at barrier + + pthread_mutex_t lock; // mutex for waiters at barrier + + volatile int maxcnt; // number of threads to wait for + + volatile int cnt; // number of waiting threads + + volatile int phase; // flag to seperate two barriers + +}; + +} + +#endif //_PTHREADBARRIERPRIVATEDATA_H_ diff --git a/src/OpenThreads/pthreads/PThreadCondition.c++ b/src/OpenThreads/pthreads/PThreadCondition.c++ new file mode 100644 index 000000000..3fc3b6c77 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadCondition.c++ @@ -0,0 +1,218 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadCondition.c++ - C++ Condition class built on top of posix threads. +// ~~~~~~~~~~~~~~~~~~~~ +// + +#if defined(_MSC_VER) || defined(__MINGW32__) +# include +#else +# include +#endif + +#include + +#include +#include "PThreadConditionPrivateData.h" +#include "PThreadMutexPrivateData.h" + +using namespace OpenThreads; + +#if defined(_MSC_VER) || defined(__MINGW32__) +int gettimeofday(struct timeval* tp, void* tzp) { + LARGE_INTEGER t; + + if(QueryPerformanceCounter(&t)) { + /* hardware supports a performance counter */ + static int been_here = 0; + static LARGE_INTEGER f; + if( !been_here ) + { + been_here = 1; + QueryPerformanceFrequency(&f); + } + tp->tv_sec = t.QuadPart/f.QuadPart; + tp->tv_usec = ((float)t.QuadPart/f.QuadPart*1000*1000) + - (tp->tv_sec*1000*1000); + } else { + /* hardware doesn't support a performance counter, so get the + time in a more traditional way. */ + DWORD t; + t = timeGetTime(); + tp->tv_sec = t / 1000; + tp->tv_usec = t % 1000; + } + + /* 0 indicates that the call succeeded. */ + return 0; +} +#endif + +//---------------------------------------------------------------------------- +// This cancel cleanup handler is necessary to ensure that the barrier's +// mutex gets unlocked on cancel. Otherwise deadlocks could occur with +// later joins. +// +void condition_cleanup_handler(void *arg) { + + pthread_mutex_t *mutex = static_cast(arg); + + pthread_mutex_unlock(mutex); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Condition::Condition() { + + PThreadConditionPrivateData *pd = + new PThreadConditionPrivateData(); + + int status = pthread_cond_init( &pd->condition, NULL ); + if (status) + { + printf("Error: pthread_cond_init(,) returned error status, status = %d\n",status); + } + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Condition::~Condition() { + + PThreadConditionPrivateData *pd = + static_cast(_prvData); + + int status = pthread_cond_destroy( &pd->condition ); + if (status) + { + printf("Error: pthread_cond_destroy(,) returned error status, status = %d\n",status); + } + + delete pd; + +} + +//---------------------------------------------------------------------------- +// +// Decription: wait on a condition +// +// Use: public. +// +int Condition::wait(Mutex *mutex) { + + PThreadConditionPrivateData *pd = + static_cast(_prvData); + + PThreadMutexPrivateData *mpd = + static_cast(mutex->_prvData); + + int status; + + pthread_cleanup_push(condition_cleanup_handler, &mpd->mutex); + + status = pthread_cond_wait( &pd->condition, &mpd->mutex ); + + pthread_cleanup_pop(0); + + return status; + + +} + +//---------------------------------------------------------------------------- +// +// Decription: wait on a condition, for a specified period of time +// +// Use: public. +// +int Condition::wait(Mutex *mutex, unsigned long int ms) { + + PThreadConditionPrivateData *pd = + static_cast(_prvData); + + PThreadMutexPrivateData *mpd = + static_cast(mutex->_prvData); + + + // wait time is now in ms milliseconds, so need to convert to seconds and nanoseconds for timespec strucuture. + unsigned int sec = ms / 1000; + unsigned int nsec = (ms % 1000) * 1000000; + + // add to the current time + struct ::timeval now; + ::gettimeofday( &now, 0 ); + + sec += now.tv_sec; + nsec += now.tv_usec*1000; + + // now pass on any overflow from nsec onto seconds. + sec += nsec / 1000000000; + nsec = nsec % 1000000000; + + struct timespec abstime; + abstime.tv_sec = sec; + abstime.tv_nsec = nsec; + + int status; + + pthread_cleanup_push(condition_cleanup_handler, &mpd->mutex); + + status = pthread_cond_timedwait( &pd->condition, &mpd->mutex, &abstime ); + + pthread_cleanup_pop(0); + + return status; + +} + +//---------------------------------------------------------------------------- +// +// Decription: signal a thread to wake up. +// +// Use: public. +// +int Condition::signal() { + + PThreadConditionPrivateData *pd = + static_cast(_prvData); + + return pthread_cond_signal( &pd->condition ); +} + +//---------------------------------------------------------------------------- +// +// Decription: signal many threads to wake up. +// +// Use: public. +// +int Condition::broadcast() { + + PThreadConditionPrivateData *pd = + static_cast(_prvData); + + return pthread_cond_broadcast( &pd->condition ); +} diff --git a/src/OpenThreads/pthreads/PThreadConditionPrivateData.h b/src/OpenThreads/pthreads/PThreadConditionPrivateData.h new file mode 100644 index 000000000..261428051 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadConditionPrivateData.h @@ -0,0 +1,44 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadConditionPrivateData.h - Private data structure for Condition +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// + +#ifndef _PTHREADCONDITIONPRIVATEDATA_H_ +#define _PTHREADCONDITIONPRIVATEDATA_H_ + +#include +#include + +namespace OpenThreads { + +class PThreadConditionPrivateData { + + friend class Condition; + +private: + + PThreadConditionPrivateData() {}; + + virtual ~PThreadConditionPrivateData() {}; + + pthread_cond_t condition; + +}; + +} + +#endif // !_PTHREADCONDITIONPRIVATEDATA_H_ diff --git a/src/OpenThreads/pthreads/PThreadMutex.c++ b/src/OpenThreads/pthreads/PThreadMutex.c++ new file mode 100644 index 000000000..733c9fcb5 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadMutex.c++ @@ -0,0 +1,154 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadMutex.c++ - C++ Mutex class built on top of posix threads. +// ~~~~~~~~~~~~~~~~ +// + +#include +#include +#include +#include "PThreadMutexPrivateData.h" + +using namespace OpenThreads; + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Mutex::Mutex() { + + pthread_mutexattr_t mutex_attr; + pthread_mutexattr_init( &mutex_attr ); + + PThreadMutexPrivateData *pd = new PThreadMutexPrivateData(); + +#ifndef __linux__ // (not available until NPTL) [ + pthread_mutexattr_settype( &mutex_attr, PTHREAD_MUTEX_ERRORCHECK ); +#endif // ] __linux__ + +#ifdef ALLOW_PRIORITY_SCHEDULING // [ + +#ifdef __sun // [ + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_NONE); +#endif // ] __sun + + //------------------------------------------------------------------------- + // Initialization is a bit tricky, since we have to be able to be aware + // that on many-to-many execution vehicle systems, we may run into + // priority inversion deadlocks if a mutex is shared between threads + // of differing priorities. Systems that do this should provide the + // following protocol attributes to prevent deadlocks. Check at runtime. + // + // PRIO_INHERIT causes any thread locking the mutex to temporarily become + // the same priority as the highest thread also blocked on the mutex. + // Although more expensive, this is the prefered method. + // + // PRIO_PROTECT causes any thread locking the mutex to assume the priority + // specified by setprioceiling. pthread_mutex_lock will fail if + // the priority ceiling is lower than the thread's priority. Therefore, + // the priority ceiling must be set to the max priority in order to + // garantee no deadlocks will occur. + // +#if defined (_POSIX_THREAD_PRIO_INHERIT) || defined (_POSIX_THREAD_PRIO_PROTECT) // [ + + if(sysconf(_POSIX_THREAD_PRIO_INHERIT)) { + + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_INHERIT); + + } else if (sysconf(_POSIX_THREAD_PRIO_PROTECT)) { + + int th_policy; + struct sched_param th_param; + pthread_getschedparam(pthread_self(), &th_policy, &th_param); + + pthread_mutexattr_setprotocol(&mutex_attr, PTHREAD_PRIO_PROTECT); + pthread_mutexattr_setprioceiling(&mutex_attr, + sched_get_priority_max(th_policy)); + + } + +#endif // ] Priority Scheduling. + +#endif // ] ALLOW_PRIORITY_SCHEDULING + + pthread_mutex_init(&pd->mutex, &mutex_attr); + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Mutex::~Mutex() { + + PThreadMutexPrivateData *pd = + static_cast(_prvData); + + pthread_mutex_destroy(&pd->mutex); + + delete pd; + +} + +//---------------------------------------------------------------------------- +// +// Decription: lock the mutex +// +// Use: public. +// +int Mutex::lock() { + + PThreadMutexPrivateData *pd = + static_cast(_prvData); + + return pthread_mutex_lock(&pd->mutex); + +} + +//---------------------------------------------------------------------------- +// +// Decription: unlock the mutex +// +// Use: public. +// +int Mutex::unlock() { + + PThreadMutexPrivateData *pd = + static_cast(_prvData); + + return pthread_mutex_unlock(&pd->mutex); + +} + +//---------------------------------------------------------------------------- +// +// Decription: test if the mutex may be locked +// +// Use: public. +// +int Mutex::trylock() { + + PThreadMutexPrivateData *pd = + static_cast(_prvData); + + return pthread_mutex_trylock(&pd->mutex); + +} diff --git a/src/OpenThreads/pthreads/PThreadMutexPrivateData.h b/src/OpenThreads/pthreads/PThreadMutexPrivateData.h new file mode 100644 index 000000000..25d967073 --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadMutexPrivateData.h @@ -0,0 +1,47 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadMutexPrivateData.h - Private data structure for Mutex +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// + +#ifndef _PTHREADMUTEXPRIVATEDATA_H_ +#define _PTHREADMUTEXPRIVATEDATA_H_ + +#include +#include + +namespace OpenThreads { + +class PThreadMutexPrivateData { + + friend class Mutex; + + friend class Condition; + +private: + + PThreadMutexPrivateData() {}; + + virtual ~PThreadMutexPrivateData() {}; + + pthread_mutex_t mutex; + +}; + +} + +#endif // !_PTHREADMUTEXPRIVATEDATA_H_ + diff --git a/src/OpenThreads/pthreads/PThreadPrivateData.h b/src/OpenThreads/pthreads/PThreadPrivateData.h new file mode 100644 index 000000000..a8297fd2b --- /dev/null +++ b/src/OpenThreads/pthreads/PThreadPrivateData.h @@ -0,0 +1,78 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// PThreadPrivateData.h - Private data structure for Thread +// ~~~~~~~~~~~~~~~~~~~~~ + +#ifndef _PTHREADPRIVATEDATA_H_ +#define _PTHREADPRIVATEDATA_H_ + +#include +#include +#include + +namespace OpenThreads { + +class PThreadPrivateData { + + //------------------------------------------------------------------------- + // We're friendly to Thread, so it can use our data. + // + friend class Thread; + + //------------------------------------------------------------------------- + // We're friendly to PThreadPrivateActions, so it can get at some + // variables. + // + friend class ThreadPrivateActions; + +private: + + PThreadPrivateData() {}; + + virtual ~PThreadPrivateData() {}; + + volatile unsigned int stackSize; + + volatile bool stackSizeLocked; + + volatile bool isRunning; + + Block threadStartedBlock; + + volatile bool isCanceled; + + volatile bool idSet; + + volatile Thread::ThreadPriority threadPriority; + + volatile Thread::ThreadPolicy threadPolicy; + + pthread_t tid; + + volatile int uniqueId; + + volatile int cpunum; + + + static int nextId; + + static pthread_key_t s_tls_key; + +}; + +} + +#endif // !_PTHREADPRIVATEDATA_H_ diff --git a/src/OpenThreads/sproc/CMakeLists.txt b/src/OpenThreads/sproc/CMakeLists.txt new file mode 100644 index 000000000..f6aeb0842 --- /dev/null +++ b/src/OpenThreads/sproc/CMakeLists.txt @@ -0,0 +1,49 @@ +# This file should only be included when using Sproc + +SET(LIB_NAME OpenThreads) +SET(LIB_PUBLIC_HEADERS ${OpenThreads_PUBLIC_HEADERS}) + +ADD_LIBRARY(${LIB_NAME} + ${OPENTHREADS_USER_DEFINED_DYNAMIC_OR_STATIC} + ${LIB_PUBLIC_HEADERS} + SharedArena.c++ + SharedArena.h + SprocBarrier.c++ + SprocBarrierPrivateData.h + SprocCondition.c++ + SprocConditionPrivateData.h + SprocMutex.c++ + SprocMutexPrivateData.h + SprocThread.c++ + SprocThreadPrivateActions.h + SprocThreadPrivateData.h + ../common/Version.cpp +) + +IF(OPENTHREADS_SONAMES) + SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION ${OPENTHREADS_VERSION} SOVERSION ${OPENTHREADS_SOVERSION}) +ENDIF(OPENTHREADS_SONAMES) + +# Do we need to link against anything for Sproc? +#TARGET_LINK_LIBRARIES(${LIB_NAME} +#) + +# Since we're building different platforms binaries in +# their respective directories, we need to set the +# link directory so it can find this location. +LINK_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} +) + +INSTALL( + TARGETS OpenThreads + ARCHIVE DESTINATION lib${LIB_POSTFIX} + LIBRARY DESTINATION lib${LIB_POSTFIX} + RUNTIME DESTINATION bin +) +INSTALL( + FILES ${OpenThreads_PUBLIC_HEADERS} + DESTINATION include/OpenThreads +) + +#commented out# INCLUDE(ModuleInstall OPTIONAL) diff --git a/src/OpenThreads/sproc/GNUmakefile b/src/OpenThreads/sproc/GNUmakefile new file mode 100644 index 000000000..1da6eda22 --- /dev/null +++ b/src/OpenThreads/sproc/GNUmakefile @@ -0,0 +1,17 @@ +TOPDIR = ../. +include $(TOPDIR)/Make/makedefs + +C++FILES = \ + SprocThread.c++ \ + SprocMutex.c++ \ + SprocBarrier.c++ \ + SprocCondition.c++ \ + SharedArena.c++ \ + $(NULL) + +INC += -I$(TOPDIR)/include -I. + +TARGET_BASENAME = OpenThreads +LIB = libOpenThreads + +include $(TOPDIR)/Make/makerules diff --git a/src/OpenThreads/sproc/SharedArena.c++ b/src/OpenThreads/sproc/SharedArena.c++ new file mode 100755 index 000000000..7f9db7a13 --- /dev/null +++ b/src/OpenThreads/sproc/SharedArena.c++ @@ -0,0 +1,256 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SharedArena.c++ - Facilities for creating/destroying shared arenas +// ~~~~~~~~~~~~~~~ + +#include +#include +#include +#include +#include +#include +#include + +#include "SharedArena.h" + +using namespace OpenThreads; + +#ifdef DEBUG +# define DPRINTF(arg) printf arg +#else +# define DPRINTF(arg) +#endif + +#define MAX_PROCS 1024 + +#define SEMAPHORE_ARENA_SIZE 500000 + +//---------------------------------------------------------------------------- +// Static arena initialization +// +usptr_t *SharedArena::_arena = 0; + +int SharedArena::_numLocks = 0; + +char *SharedArena::_arenaName = 0; + + +void SharedArena::initArena() { + + _arenaName = tmpnam(0); + DPRINTF(("Creating arena: %s\n", _arenaName)); + + if (unlink(_arenaName) < 0) { + if (errno != ENOENT) { + perror("unlink"); + exit(1); + } + } + + if (usconfig(CONF_INITUSERS, MAX_PROCS) < 0) { + perror("usconfig1"); + exit(1); + } + +#ifdef OT_USESHAREDONLY + if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) { + perror("usconfig2"); + exit(1); + } +#endif + + char *sema_arena_size_string = getenv("OPENTHREADS_SEMAPHORE_ARENA_SIZE"); + unsigned long int sema_arena_size; + if(sema_arena_size_string != 0L) { + sema_arena_size = atol(sema_arena_size_string); + } else { + sema_arena_size = SEMAPHORE_ARENA_SIZE; + } + + if (usconfig(CONF_INITSIZE,sema_arena_size) < 0) { + perror("usconfig3"); + exit(1); + } + + + if ((_arena = usinit(_arenaName)) == 0) { + perror("usinit"); + exit(1); + } +} + +void SharedArena::removeArena() { + + DPRINTF(("Removing arena: %s\n", _arenaName)); +#ifndef OT_USESHAREDONLY + + if (unlink(_arenaName) < 0) { + perror("unlink"); + exit(1); + } +#endif + +} + +ulock_t SharedArena::allocLock() { + + if(_numLocks == 0) initArena(); + + assert(_arena != 0); + + ulock_t lock; + if ((lock = usnewlock(_arena)) == 0) { + perror("usnewlock"); + printf("Num Locks: %d\n", _numLocks); + exit(1); + } + ++_numLocks; + return lock; +} + +barrier_t *SharedArena::allocBarrier() { + + if(_numLocks == 0) initArena(); + + assert(_arena != 0); + barrier_t *bar; + if ((bar= new_barrier(_arena)) == 0) { + perror("new_barrier"); + exit(1); + } + ++_numLocks; + return bar; + +} + +int SharedArena::lock(ulock_t lock) { + + return ussetlock(lock); +} + +int SharedArena::unlock(ulock_t lock) { + + return usunsetlock(lock); +} + +int SharedArena::trylock(ulock_t lock) { + + return ustestlock(lock); +} + +void SharedArena::deleteLock(ulock_t lock) { + + assert(_arena != 0); + usfreelock(lock, _arena); + --_numLocks; + if(_numLocks == 0) { + removeArena(); + } +} + +void SharedArena::initBarrier(barrier_t *b) { + init_barrier(b); +} + +void SharedArena::freeBarrier(barrier_t *b) { + assert(_arena != 0); + free_barrier(b); + b = 0; + --_numLocks; + if(_numLocks == 0) { + removeArena(); + } +} + +void SharedArena::block(barrier_t *b, unsigned int n) { + barrier(b, n); +} + +usema_t *SharedArena::allocSema() { + + if(_numLocks == 0) initArena(); + assert(_arena != 0); + + usema_t *sema; + sema = usnewpollsema(_arena, 0); + if(sema == 0) { + perror("usnewpollsema"); + printf("NUM SEMAS: %d\n", _numLocks); + exit(1); + } + ++_numLocks; + return sema; + +} + +int SharedArena::getSemaFd(usema_t *sema) { + + int returnval; + returnval = usopenpollsema(sema, S_IRWXU | S_IRWXG | S_IRWXO); + if(0 > returnval) { + perror("usopenpollsema"); + exit(1); + } + return returnval; + +} + + + +int SharedArena::pSema(usema_t *sema) { + + return uspsema(sema); + +} + +int SharedArena::vSema(usema_t *sema) { + + return usvsema(sema); + +} + +int SharedArena::testSema(usema_t *sema) { + + return ustestsema(sema); + +} + +int SharedArena::closeSemaFd(usema_t *sema) { + + int returnval; + returnval = usclosepollsema(sema); + if(returnval != 0) { + perror("usclosepollsema"); + exit(1); + } + + return returnval; + +} + +int SharedArena::freeSema(usema_t *sema) { + + assert(_arena != 0); + usfreepollsema(sema, _arena); + --_numLocks; + if(_numLocks == 0) { + removeArena(); + } + + return 0; +} + +#undef OT_USESHAREDONLY diff --git a/src/OpenThreads/sproc/SharedArena.h b/src/OpenThreads/sproc/SharedArena.h new file mode 100755 index 000000000..df3d678f6 --- /dev/null +++ b/src/OpenThreads/sproc/SharedArena.h @@ -0,0 +1,87 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// SharedArena.h - Facilities for creating/destroying shared arenas +// ~~~~~~~~~~~~~ + +#ifndef _SHAREDARENA_H_ +#define _SHAREDARENA_H_ + +#include +#include +#include +#include + +namespace OpenThreads { + +#define OT_USESHAREDONLY + +class SharedArena { + + friend class Mutex; + + friend class Barrier; + + friend class Condition; + +private: + + static void initArena(); + + static void removeArena(); + + static ulock_t allocLock(); + + static barrier_t *allocBarrier(); + + static usema_t *allocSema(); + + static int getSemaFd(usema_t *sema); + + static int pSema(usema_t *sema); + + static int vSema(usema_t *sema); + + static int testSema(usema_t *sema); + + static int closeSemaFd(usema_t *sema); + + static int freeSema(usema_t *sema); + + static int lock(ulock_t lock); + + static int unlock(ulock_t lock); + + static int trylock(ulock_t lock); + + static void deleteLock(ulock_t lock); + + static void initBarrier(barrier_t *b); + + static void freeBarrier(barrier_t *b); + + static void block(barrier_t *b, unsigned int n); + +private: + + static usptr_t *_arena; + + static int _numLocks; + + static char *_arenaName; +}; + +} + +#endif // !_SHAREDARENA_H_ diff --git a/src/OpenThreads/sproc/SprocBarrier.c++ b/src/OpenThreads/sproc/SprocBarrier.c++ new file mode 100755 index 000000000..2ffa4c6d8 --- /dev/null +++ b/src/OpenThreads/sproc/SprocBarrier.c++ @@ -0,0 +1,229 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocBarrier.c++ - C++ Barrier class built on top of IRIX process threads. +// ~~~~~~~~~~~~~~~~ + +#include +#include +#include "SprocBarrierPrivateData.h" +#include "SharedArena.h" +#include "SprocThreadPrivateActions.h" + +#ifndef USE_IRIX_NATIVE_BARRIER + +#include +#include + +#endif + +#ifdef DEBUG +#define DPRINTF(arg) printf arg; fflush(stdout); +#else +#define DPRINTF(arg) +#endif + +using namespace OpenThreads; + +//---------------------------------------------------------------------------- +// This cancel cleanup handler is necessary to ensure that the barrier's +// mutex gets unlocked on cancel. Otherwise deadlocks could occur with +// later joins. +// +void barrier_cleanup_handler(void *arg) { + + DPRINTF(("(SPROC BARRIER) cleanup handler called on pid %d\n", getpid())); + + Mutex *mutex = static_cast(arg); + + if(mutex->trylock() == 1) + mutex->unlock(); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Barrier::Barrier(int numThreads) { + + SprocBarrierPrivateData *pd = new SprocBarrierPrivateData(); + +#ifdef USE_IRIX_NATIVE_BARRIER + + pd->barrier = SharedArena::allocBarrier(); + pd->numThreads = numThreads; + +#else + + pd->cnt = 0; + pd->phase = 0; + pd->maxcnt = numThreads; + +#endif + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Barrier::~Barrier() { + + SprocBarrierPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_IRIX_NATIVE_BARRIER + + SharedArena::freeBarrier(pd->barrier); + +#endif + + delete pd; +} + +//---------------------------------------------------------------------------- +// +// Decription: Reset the barrier to its original state +// +// Use: public. +// +void Barrier::reset() { + + SprocBarrierPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_IRIX_NATIVE_BARRIER + + SharedArena::initBarrier(pd->barrier); + +#else + + pd->cnt = 0; + pd->phase = 0; + +#endif + +} + +//---------------------------------------------------------------------------- +// +// Decription: Block until numThreads threads have entered the barrier. +// +// Use: public. +// +void Barrier::block(unsigned int numThreads) { + + SprocBarrierPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_IRIX_NATIVE_BARRIER + + if(numThreads == 0) { + SharedArena::block(pd->barrier, pd->numThreads); + } else { + SharedArena::block(pd->barrier, numThreads); + } + +#else + + pd->_mutex.lock(); + + if(numThreads != 0) pd->maxcnt = numThreads; + + int my_phase; + + my_phase = pd->phase; + ++pd->cnt; + + DPRINTF(("(SPROC BARRIER %d) block, count=%d, maxThreads=%d, phase=%d\n", + getpid(), pd->cnt, pd->maxcnt, pd->phase)); + + if(pd->cnt == pd->maxcnt) { // I am the last one + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pd->_cond.broadcast(); + } + + while (pd->phase == my_phase) { + ThreadPrivateActions::PushCancelFunction(barrier_cleanup_handler, + &pd->_mutex); + pd->_cond.wait(&pd->_mutex); + + ThreadPrivateActions::PopCancelFunction(); + } + + pd->_mutex.unlock(); + +#endif + +} + +//---------------------------------------------------------------------------- +// +// Description: Release the barrier, now. +// +// Use: public. +// +void Barrier::release() { + + SprocBarrierPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_IRIX_NATIVE_BARRIER + + printf("ERROR >>>>> Barrier::release() cannot be implemented using native IRIX Barriers !!!\n"); + +#else + + int my_phase; + pd->_mutex.lock(); + + my_phase = pd->phase; + + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pd->_cond.broadcast(); + + pd->_mutex.unlock(); + +#endif + +} + +//---------------------------------------------------------------------------- +// +// Description: Return the number of threads currently blocked in the barrier +// +// Use: public +// +int Barrier::numThreadsCurrentlyBlocked() { + + SprocBarrierPrivateData *pd = + static_cast(_prvData); + + int numBlocked = -1; + pd->_mutex.lock(); + numBlocked = pd->cnt; + pd->_cond.broadcast(); + return numBlocked; + +} diff --git a/src/OpenThreads/sproc/SprocBarrierPrivateData.h b/src/OpenThreads/sproc/SprocBarrierPrivateData.h new file mode 100755 index 000000000..02a11b4cc --- /dev/null +++ b/src/OpenThreads/sproc/SprocBarrierPrivateData.h @@ -0,0 +1,67 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// SprocBarrierPrivateData.h - private data structure for barrier +// ~~~~~~~~~~~~~~~~~~~~~~~~~ + +#ifndef _SPROCBARRIERPRIVATEDATA_H_ +#define _SPROCBARRIERPRIVATEDATA_H_ + +#include +#include + +#ifndef USE_IRIX_NATIVE_BARRIER + +#include +#include + +#endif + +namespace OpenThreads { + +class SprocBarrierPrivateData { + + friend class Barrier; + +private: + + SprocBarrierPrivateData() {}; + + virtual ~SprocBarrierPrivateData() {}; + +#ifdef USE_IRIX_NATIVE_BARRIER + + barrier_t *barrier; + + unsigned int numThreads; + +#else + + OpenThreads::Condition _cond; + + OpenThreads::Mutex _mutex; + + volatile int maxcnt; + + volatile int cnt; + + volatile int phase; + +#endif + +}; + +} + +#endif //_SPROCBARRIERPRIVATEDATA_H_ diff --git a/src/OpenThreads/sproc/SprocCondition.c++ b/src/OpenThreads/sproc/SprocCondition.c++ new file mode 100755 index 000000000..3b56af59b --- /dev/null +++ b/src/OpenThreads/sproc/SprocCondition.c++ @@ -0,0 +1,306 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocCondition.c++ - C++ Condition class built on sprocs. +// ~~~~~~~~~~~~~~~~~~ + +#include +#include "SprocConditionPrivateData.h" +#include +#include "SharedArena.h" +#include "SprocThreadPrivateActions.h" +#include +#include + +using namespace OpenThreads; + +#ifdef DEBUG + +#define DPRINTF(arg) printf arg; fflush(stdout); +#define DPRINTLIST(arg) ConditionDebug::printList arg; fflush(stdout); + +namespace OpenThreads { + +class ConditionDebug { + + friend class Condition; + +private: + + static void printList(std::list &pid_list) { + + std::list::iterator iter; + int counter = 0; + printf("(SPROC CONDITION %d) ", getpid()); + for(iter=pid_list.begin(); iter!=pid_list.end();++iter) { + printf("Pid [%d]=%d, ", counter, *iter); + ++counter; + } + printf("\b\n"); + + } + +}; + +} + +#else + +#define DPRINTF(arg) +#define DPRINTLIST(arg) + +#endif + +void condition_alarm_handler(int signal) { + + //DPRINTF(("(SPROC CONDITION) signal alarm handler called.\n")); + + sigset(SIGALRM, SIG_DFL); + + unblockproc(getpid()); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Condition::Condition() { + + SprocConditionPrivateData *pd = + new SprocConditionPrivateData(); + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Condition::~Condition() { + + SprocConditionPrivateData *pd = + static_cast(_prvData); + + pd->mutex.lock(); + DPRINTF(("(SPROC CONDITION) : In destructor\n")); + DPRINTLIST((pd->pid_list)); + + //------------------------------------------------------------------------- + // Destroy all remaining in the linked-list of waiters (pids). + // + pd->pid_list.clear(); + + delete pd; + _prvData = 0; + +} + +//---------------------------------------------------------------------------- +// +// Decription: wait on a condition +// +// Use: public. +// +int Condition::wait(Mutex *mutex) { + + return wait(mutex, 0); + +} + +//---------------------------------------------------------------------------- +// +// Decription: wait on a condition +// +// Use: public. +// +int Condition::wait(Mutex *mutex, unsigned long int ms) { + + unsigned int sec; + unsigned int usec; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + pid_t mypid = getpid(); + + SprocConditionPrivateData *pd = + static_cast(_prvData); + + if(ms != 0) { + + // Wait for ms milliseconds + sec = ms / 1000; + usec = (ms % 1000) * 1000; + tv.tv_sec = sec; + tv.tv_usec = usec; + + DPRINTF(("(SPROC CONDITION) : PID %d timeout values [%d | %d]\n", + mypid, tv.tv_sec, tv.tv_usec)); + + } + + pd->mutex.lock(); + + pd->pid_list.push_front(mypid); + + pd->mutex.unlock(); + + DPRINTF(("(SPROC CONDITION) : PID %d going to blockproc\n", + mypid)); + + int status = 0; + + status = setblockproccnt(mypid, 0); + + // If we're doing a timout, setup the signal handler to deal with it. + if(tv.tv_sec != 0 || tv.tv_usec != 0) { + + DPRINTF(("(SPROC CONDITION) : PID %d setting timeout condition\n", + mypid)); + + sigset(SIGALRM, condition_alarm_handler); + + struct timeval recur; + recur.tv_sec = 0; + recur.tv_usec = 0; + + itimerval itv; + itv.it_interval = recur; + itv.it_value = tv; + + setitimer(ITIMER_REAL, &itv, NULL); + + } + + mutex->unlock(); + + ThreadPrivateActions::ThreadCancelTest(); + + status = blockproc(mypid); + + ThreadPrivateActions::ThreadCancelTest(); + + mutex->lock(); + + DPRINTF(("(SPROC CONDITION) : PID %d, returned from blockproc %d\n", + mypid, status)); + + //------------------------------------------------------------------------- + // Pull the pid from the list + // + pd->mutex.lock(); + + DPRINTLIST((pd->pid_list)); + +#ifndef DEBUG + + // KLUDGE - can optimized this by just doing -remove()- + std::list::iterator iter; + iter = pd->pid_list.begin(); + while(iter != pd->pid_list.end()) { + + if(*iter == mypid) { + DPRINTF(("(SPROC CONDITION) : PID %d removed itself from the list\n", + mypid)); + + pd->pid_list.remove(mypid); + iter = pd->pid_list.begin(); + } else { + ++iter; + } + + } + +#else + pd->pid_list.remove(mypid); +#endif + + DPRINTLIST((pd->pid_list)); + + pd->mutex.unlock(); + + if(status == -1) { + return status; + } + + return 0; +} + +//---------------------------------------------------------------------------- +// +// Decription: signal a thread to wake up. +// +// Use: public. +// +int Condition::signal() { + + ThreadPrivateActions::ThreadCancelTest(); + + SprocConditionPrivateData *pd = + static_cast(_prvData); + + pd->mutex.lock(); + if(pd->pid_list.empty()) { + DPRINTF(("(SPROC CONDITION) : No threads to signal\n")); + pd->mutex.unlock(); // Remember to release the mutex. + return 0; + } + //------------------------------------------------------------------------- + // Perform an unblockproc on the first pid in the list. + // + DPRINTF(("(SPROC CONDITION) : PID %d signaling pid %d\n", + getpid(), pd->pid_list.front())); + int status = unblockproc(pd->pid_list.front()); + pd->mutex.unlock(); + return status; +} + +//---------------------------------------------------------------------------- +// +// Decription: signal all threads to wake up. +// +// Use: public. +// +int Condition::broadcast() { + + + ThreadPrivateActions::ThreadCancelTest(); + + SprocConditionPrivateData *pd = + static_cast(_prvData); + + pd->mutex.lock(); + + std::list::iterator iter; + for(iter = pd->pid_list.begin(); + iter != pd->pid_list.end(); + ++iter) { + + DPRINTF(("(SPROC CONDITION) Broadcast to pid[%d]\n", *iter)); + unblockproc(*iter); + } + + pd->mutex.unlock(); + + return 0; +} + + diff --git a/src/OpenThreads/sproc/SprocConditionPrivateData.h b/src/OpenThreads/sproc/SprocConditionPrivateData.h new file mode 100755 index 000000000..a758412b2 --- /dev/null +++ b/src/OpenThreads/sproc/SprocConditionPrivateData.h @@ -0,0 +1,82 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocConditionPrivateData.h - Private data structure for Condition +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#ifndef _SPROCCONDITIONPRIVATEDATA_H_ +#define _SPROCCONDITIONPRIVATEDATA_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace OpenThreads { + +class SemaLink { + + friend class SprocConditionPrivatedata; + + friend class Condition; + + friend class ConditionDebug; + +private: + + SemaLink() {}; + + virtual ~SemaLink() {}; + + SemaLink *next; + + usema_t *sema; + + int select_cond; // 0=pre-select, 1=in-select, 2=post-select + +}; + +class SprocConditionPrivateData { + + friend class Condition; + +private: + + SprocConditionPrivateData() { + + pid_list.clear(); + + }; + + virtual ~SprocConditionPrivateData() { + + pid_list.clear(); + + }; + + std::list pid_list; + + Mutex mutex; + +}; + +} + +#endif // !_SPROCCONDITIONPRIVATEDATA_H_ diff --git a/src/OpenThreads/sproc/SprocMutex.c++ b/src/OpenThreads/sproc/SprocMutex.c++ new file mode 100755 index 000000000..700927c1d --- /dev/null +++ b/src/OpenThreads/sproc/SprocMutex.c++ @@ -0,0 +1,126 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocMutex.c++ - C++ Mutex class built on top of posix threads. +// ~~~~~~~~~~~~~~ + +#include +#include +#include +#include + +#include +#include "SharedArena.h" +#include "SprocMutexPrivateData.h" +#include "SprocThreadPrivateActions.h" + +using namespace OpenThreads; + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Mutex::Mutex() { + + SprocMutexPrivateData *pd = new SprocMutexPrivateData(); + + pd->mutex = SharedArena::allocLock(); + + _prvData = static_cast(pd); + +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Mutex::~Mutex() { + + SprocMutexPrivateData *pd = + static_cast(_prvData); + + SharedArena::deleteLock(pd->mutex); + + delete pd; + +} + +//---------------------------------------------------------------------------- +// +// Decription: lock the mutex +// +// Use: public. +// +int Mutex::lock() { + + ThreadPrivateActions::ThreadCancelTest(); + + SprocMutexPrivateData *pd = + static_cast(_prvData); + + int status = SharedArena::lock(pd->mutex); + + if(status == -1) { + return status; + } + + if(status == 1) { + return 0; + } else { + return 1; + } + return 0; +} + +//---------------------------------------------------------------------------- +// +// Decription: unlock the mutex +// +// Use: public. +// +int Mutex::unlock() { + + SprocMutexPrivateData *pd = + static_cast(_prvData); + + int status = SharedArena::unlock(pd->mutex); + + ThreadPrivateActions::ThreadCancelTest(); + + return status; + +} + +//---------------------------------------------------------------------------- +// +// Decription: test if the mutex may be locked +// +// Use: public. +// +int Mutex::trylock() { + + SprocMutexPrivateData *pd = + static_cast(_prvData); + + int status = SharedArena::trylock(pd->mutex); + + return status; + +} + diff --git a/src/OpenThreads/sproc/SprocMutexPrivateData.h b/src/OpenThreads/sproc/SprocMutexPrivateData.h new file mode 100755 index 000000000..8a09318f4 --- /dev/null +++ b/src/OpenThreads/sproc/SprocMutexPrivateData.h @@ -0,0 +1,45 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocMutexPrivateData.h - Private data structure for Mutex +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#ifndef _SPROCMUTEXPRIVATEDATA_H_ +#define _SPROCMUTEXPRIVATEDATA_H_ + +#include +#include + +namespace OpenThreads { + +class SprocMutexPrivateData { + + friend class SprocThreadPrivateActions; + + friend class Mutex; + +private: + + SprocMutexPrivateData() {}; + + virtual ~SprocMutexPrivateData() {}; + + ulock_t mutex; + +}; + +} + +#endif // _SPROCMUTEXPRIVATEDATA_H_ diff --git a/src/OpenThreads/sproc/SprocThread.c++ b/src/OpenThreads/sproc/SprocThread.c++ new file mode 100755 index 000000000..c3b3b1321 --- /dev/null +++ b/src/OpenThreads/sproc/SprocThread.c++ @@ -0,0 +1,823 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocThread.c++ - C++ Thread class built on top of IRIX sproc. +// ~~~~~~~~~~~~~~~ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SprocMutexPrivateData.h" +#include "SprocThreadPrivateData.h" +#include "SprocThreadPrivateActions.h" + +using namespace OpenThreads; + +extern int errno; +const char *OPENTHREAD_VERSION_STRING = "Sproc Thread Model, v1.1 ("__DATE__" "__TIME__")"; + +#ifdef DEBUG +#define DPRINTF(arg) printf arg; fflush(stdout); +#else +#define DPRINTF(ARG) +#endif + +static void sproc_dead_child_sig_handler(int sigid); + +//----------------------------------------------------------------------------- +// Initialize the static unique ids. +// +int SprocThreadPrivateData::nextId = 0; + +//----------------------------------------------------------------------------- +// Initialize thread master priority level +// +Thread::ThreadPriority Thread::s_masterThreadPriority = + Thread::THREAD_PRIORITY_MAX; + +bool Thread::s_isInitialized = false; + +std::list ThreadPrivateActions::s_threadList; + +void ThreadPrivateActions::ThreadCancelTest() { + + OpenThreads::Thread *t = GetThread(getpid()); + + if(t != 0L) { + + SprocThreadPrivateData *pd = + static_cast(t->_prvData); + + bool *dieflag = GetDeathFlag(t); + + if(*dieflag==false) return; + + DPRINTF(("(SPROC THREAD) Thread Cancel Test Passed for %d\n", + getpid())); + + if(!pd->cancelFuncStack.empty()) + pd->cancelFuncStack.top().routine(pd->cancelFuncStack.top().arg); + + t->cancelCleanup(); + pd->isRunning = false; + + exit(1); + } +} + +bool *ThreadPrivateActions::GetDeathFlag(Thread *thread) { + + SprocThreadPrivateData *pd = + static_cast(thread->_prvData); + + return (bool *)(&(pd->dieFlag)); +} + +Thread *ThreadPrivateActions::GetThread(pid_t thread_id) { + + std::list::iterator iter; + for(iter = s_threadList.begin(); + iter != s_threadList.end(); + ++iter) { + + Thread *t = *iter; + if(t->getProcessId() == thread_id) return t; + + } + + return 0L; // no thread found; + +}; + +void ThreadPrivateActions::ThreadCancelHandler(int sigid) { + + Thread *t = GetThread(getpid()); + + if(t != 0L) { + + bool * dieflag = GetDeathFlag(t); + + *dieflag = true; + + sigset(SIGINT, SIG_DFL); + unblockproc(getpid()); + } +} + +//------------------------------------------------------------------------- +// standard start routine. +// +void ThreadPrivateActions::StartThread(void *data) +{ + + Thread *thread = static_cast(data); + + if (thread->_prvData==0) return; + + AddThread(thread); + + *((Thread **)&PRDA->usr_prda) = (Thread *)thread; + + SetThreadSchedulingParams(thread); + + SprocThreadPrivateData *pd = + static_cast(thread->_prvData); + + sigset(SIGINT, ThreadCancelHandler); + + size_t defaultStackSize; + prctl(PR_GETSTACKSIZE, &defaultStackSize); + + if(defaultStackSize < pd->stackSize) { + prctl(PR_SETSTACKSIZE, pd->stackSize); + } + + prctl(PR_GETSTACKSIZE, &pd->stackSize); + + pd->stackSizeLocked = true; + + pd->isRunning = true; + + // release the thread that created this thread. + pd->threadStartedBlock.release(); + + thread->run(); + + pd->isRunning = false; + + RemoveThread(thread); + + if(pd->detached == true ) { + exit(0); + } + + return; + +}; + +void ThreadPrivateActions::AddThread(Thread *thread) { + + s_threadList.push_front(thread); + + }; + +void ThreadPrivateActions::RemoveThread(Thread *thread) { + s_threadList.remove(thread); +}; + +void ThreadPrivateActions::PrintThreadSchedulingInfo(Thread *thread) { + + int status, my_policy, min_priority, max_priority; + struct sched_param my_param; + + status = sched_getparam(thread->getProcessId(), + &my_param); + + my_policy = sched_getscheduler(thread->getProcessId()); + + if(status != 0 || my_policy == -1) { + + printf("THREAD INFO (%d) : Get sched param: %s/%s\n", + thread->getProcessId(), + strerror(status), + strerror(errno)); + } else { + printf( + "THREAD INFO (%d) : Thread running at %s / Priority: %d\n", + thread->getProcessId(), + (my_policy == SCHED_FIFO ? "SCHEDULE_FIFO" + : (my_policy == SCHED_RR ? "SCHEDULE_ROUND_ROBIN" + : (my_policy == SCHED_TS ? "SCHEDULE_TIME_SHARE" + : (my_policy == SCHED_OTHER ? "SCHEDULE_OTHER" + : "UNKNOWN")))), + my_param.sched_priority); + + max_priority = sched_get_priority_max(my_policy); + min_priority = sched_get_priority_min(my_policy); + + printf( + "THREAD INFO (%d) : Max priority: %d, Min priority: %d\n", + thread->getProcessId(), + max_priority, min_priority); + + } + +} + +int ThreadPrivateActions::SetThreadSchedulingParams(Thread *thread) { + + int status; + + int th_priority; + int max_priority, nominal_priority, min_priority; + + max_priority = 0; // This is as high as we can regularly go. + min_priority = 20; + nominal_priority = (max_priority + min_priority)/2; + + switch(thread->getSchedulePriority()) { + + case Thread::THREAD_PRIORITY_MAX: + th_priority = max_priority; + break; + + case Thread::THREAD_PRIORITY_HIGH: + th_priority = (max_priority + nominal_priority)/2; + break; + + case Thread::THREAD_PRIORITY_NOMINAL: + th_priority = nominal_priority; + break; + + case Thread::THREAD_PRIORITY_LOW: + th_priority = (min_priority + nominal_priority)/2; + break; + + case Thread::THREAD_PRIORITY_MIN: + th_priority = min_priority; + break; + + default: + th_priority = max_priority; + break; + + } + + status = setpriority(PRIO_PROCESS, thread->getProcessId(), + th_priority); + + if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0) + PrintThreadSchedulingInfo(thread); + + return status; +}; + +void ThreadPrivateActions::PushCancelFunction(void (*routine)(void *), void *arg) { + + Thread *thread = GetThread(getpid()); + + if(thread != 0L) { + SprocThreadPrivateData *pd = + static_cast(thread->_prvData); + + SprocThreadPrivateData::CancelFuncStruct c; + + pd->cancelFuncStack.push(c); + + SprocThreadPrivateData::CancelFuncStruct *cft = &(pd->cancelFuncStack.top()); + + cft->routine = routine; + cft->arg = arg; + } +} + +void ThreadPrivateActions::PopCancelFunction() { + + Thread *thread = GetThread(getpid()); + + if(thread != 0L) { + + SprocThreadPrivateData *pd = + static_cast(thread->_prvData); + + if(!pd->cancelFuncStack.empty()) + pd->cancelFuncStack.pop(); + } +} + +//---------------------------------------------------------------------------- +// +// Description: Set the concurrency level (no-op) +// +// Use static public +// +int Thread::SetConcurrency(int concurrencyLevel) { + + return -1; + +}; + +//---------------------------------------------------------------------------- +// +// Description: Get the concurrency level +// +// Use static public +// +int Thread::GetConcurrency() { + + return -1; + +}; + +//---------------------------------------------------------------------------- +// +// Decription: Constructor +// +// Use: public. +// +Thread::Thread() { + + if(!s_isInitialized) Init(); + + SprocThreadPrivateData *pd = new SprocThreadPrivateData(); + pd->stackSize = 128*1024; // Set a minimum of 128K bytes if possible. + pd->stackSizeLocked = false; + pd->isRunning = false; + pd->isCanceled = false; + pd->idSet = false; + pd->cancelActive = true; + pd->detached = false; + pd->uniqueId = pd->nextId; + pd->nextId++; + pd->threadPriority = Thread::THREAD_PRIORITY_DEFAULT; + pd->threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT; + + _prvData = static_cast(pd); +} + +//---------------------------------------------------------------------------- +// +// Decription: Destructor +// +// Use: public. +// +Thread::~Thread() +{ + DPRINTF(("(SPROC THREAD) %s:%d, In OpenThreads::Thread destructor\n", + __FILE__, __LINE__)); + + SprocThreadPrivateData *pd = + static_cast(_prvData); + + if(pd->isRunning) + { + + DPRINTF(("(SPROC THREAD) %s:%d, about to kill OpenThreads::Thread\n", + __FILE__, __LINE__)); + + + //------------------------------------------------------------------- + // Kill the process when the thread is destroyed. + // + cancel(); + + while (pd->isRunning == true) { + ::usleep(1); + } + + } + + + DPRINTF(("(SPROC THREAD) %s:%d, Thread destroying private data.\n", + __FILE__, __LINE__)); + + + delete pd; + + _prvData = 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Initialize Threading +// +// Use: public. +// +void Thread::Init() { + + if(s_isInitialized) return; + +#ifdef GP_DEBUG + fprintf(stderr, "%s\n", OPENTHREAD_VERSION_STRING); +#endif + + s_masterThreadPriority = Thread::THREAD_PRIORITY_MAX; + + s_isInitialized = true; + +} + +//----------------------------------------------------------------------------- +// +// Description: Return a pointer to the currently executing thread +// +// Use: public +// +Thread *Thread::CurrentThread() { + + return (*(Thread **)&PRDA->usr_prda); + +} + +//----------------------------------------------------------------------------- +// +// Description: Get a unique identifier for this thread. +// +// Use: public +// +int Thread::getThreadId() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + return pd->uniqueId; +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's process id +// +// Use: public +// +size_t Thread::getProcessId() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + if(pd->idSet == false) return getpid(); + + return (size_t)(pd->pid); + +} + +//----------------------------------------------------------------------------- +// +// Description: Determine if the thread is running +// +// Use: public +// +bool Thread::isRunning() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + return pd->isRunning; + +} + +//----------------------------------------------------------------------------- +// +// Description: Start the thread. +// +// Use: public +// +int Thread::start() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->threadStartedBlock.reset(); + + int pid = sproc(ThreadPrivateActions::StartThread, + PR_SALL, + static_cast(this)); + + // PR_SADDR | PR_SDIR | PR_SUMASK | PR_SULIMIT | PR_SID, + + if(pid < 0) { + perror("sproc encountered an error"); + return -1; + } + + //----------------------------------------------------------------- + // Make the thread runnable anywhere. + // + sysmp(MP_RUNANYWHERE_PID, pid); + + pd->pid = pid; + pd->idSet = true; + + // wait till the thread has actually started. + pd->threadStartedBlock.block(); + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Alternate thread start routine. +// +// Use: public +// +int Thread::startThread() +{ + if (_prvData) return start(); + else return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Join the thread. +// +// Use: public +// +int Thread::detach() { + + int status = 0; + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->detached=true; + sigset(SIGCLD, sproc_dead_child_sig_handler); + + return status; + +} + +//----------------------------------------------------------------------------- +// +// Description: Join the thread. +// +// Use: public +// +int Thread::join() { + + int status; + + return waitpid((pid_t)getProcessId(), &status, 0); + //return status; + +} + +//----------------------------------------------------------------------------- +// +// Description: test the cancel state of the thread. +// +// Use: public +// +int Thread::testCancel() { + + if(getpid() != getProcessId()) return -1; + + ThreadPrivateActions::ThreadCancelTest(); + + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Cancel the thread. +// +// Use: public +// +int Thread::cancel() { + + int status = 0; + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + if(pd->cancelActive) { + + status = kill((pid_t)getProcessId(), SIGINT); + }; + + return status; + +} + +//----------------------------------------------------------------------------- +// +// Description: Disable cancelibility +// +// Use: public +// +int Thread::setCancelModeDisable() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->cancelActive = false; + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel immediately +// +// Use: public +// +int Thread::setCancelModeAsynchronous() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->cancelActive = true; + + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel at the next convienent point. +// +// Use: public +// +int Thread::setCancelModeDeferred() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->cancelActive = true; + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's schedule priority (if able) +// +// Use: public +// +int Thread::setSchedulePriority(ThreadPriority priority) { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + pd->threadPriority = priority; + + if(pd->isRunning) + return ThreadPrivateActions::SetThreadSchedulingParams(this); + else + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's schedule priority (if able) +// +// Use: public +// +int Thread::getSchedulePriority() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + return pd->threadPriority; + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::setSchedulePolicy(ThreadPolicy policy) { + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::getSchedulePolicy() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + return pd->threadPolicy; + +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's desired stack size +// +// Use: public +// +int Thread::setStackSize(size_t stackSize) { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + if(pd->stackSizeLocked == true) return 13; // EACESS + + pd->stackSize = stackSize; + + return 0; + +} + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's stack size. +// +// Use: public +// +size_t Thread::getStackSize() { + + SprocThreadPrivateData *pd = + static_cast (_prvData); + + return pd->stackSize; + +} + +//----------------------------------------------------------------------------- +// +// Description: Print the thread's scheduling information to stdout. +// +// Use: public +// +void Thread::printSchedulingInfo() { + + ThreadPrivateActions::PrintThreadSchedulingInfo(this); + +} + +//----------------------------------------------------------------------------- +// +// Description: Yield the processor +// +// Use: protected +// +int Thread::YieldCurrentThread() { + + return sched_yield(); + +} + +//----------------------------------------------------------------------------- +// Description: sleep +// +// Use: public +// +int Thread::microSleep(unsigned int microsec) +{ + return ::usleep(microsec); +} + +static void sproc_dead_child_sig_handler(int sigid) { + +#ifdef DEBUG + int pid, status; + pid = wait(&status); + DPRINTF(("(SPROC THREAD) Dead Child Handler Caught Signal, Reaped %d\n", + pid)); +#endif + + sigset(SIGCLD, sproc_dead_child_sig_handler); + +} + +int Thread::setProcessorAffinity( unsigned int cpunum ) +{ + return -1; +} + +//----------------------------------------------------------------------------- +// +// Description: Get the number of processors +// +int OpenThreads::GetNumberOfProcessors() +{ + return 1; +} + +int OpenThreads::SetProcessorAffinityOfCurrentThread(unsigned int cpunum) +{ + if (cpunum<0) return -1; + + Thread::Init(); + + Thread* thread = Thread::CurrentThread(); + if (thread) + { + return thread->setProcessorAffinity(cpunum); + } + else + { + // non op right now, needs implementation. + return -1; + } +} diff --git a/src/OpenThreads/sproc/SprocThreadPrivateActions.h b/src/OpenThreads/sproc/SprocThreadPrivateActions.h new file mode 100755 index 000000000..a024eb4bb --- /dev/null +++ b/src/OpenThreads/sproc/SprocThreadPrivateActions.h @@ -0,0 +1,71 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// SprocThreadPrivateActions.c++ - Thread private actions for sprocs +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#include +#include + +#ifndef SPROC_THREAD_PRIVATE_ACTIONS +#define SPROC_THREAD_PRIVATE_ACTIONS + +namespace OpenThreads { + + class ThreadPrivateActions { + + //------------------------------------------------------------------------- + // We're friendly to Thread, so it can issue the methods. + // + friend class Thread; + + public: + + static void ThreadCancelTest(); + + static void PushCancelFunction(void (*routine)(void *), void *arg); + + static void PopCancelFunction(); + + private: + + static bool *GetDeathFlag(Thread *thread); + + static Thread *GetThread(pid_t thread_id); + + static void ThreadCancelHandler(int sigid); + + //------------------------------------------------------------------------- + // standard start routine. + // + static void StartThread(void *data); + + static void AddThread(Thread *thread); + + static void RemoveThread(Thread *thread); + + static void PrintThreadSchedulingInfo(Thread *thread); + + static int SetThreadSchedulingParams(Thread *thread); + + private: + + static std::list s_threadList; + + }; + +} + +#endif // !SPROC_THREAD_PRIVATE_ACTIONS diff --git a/src/OpenThreads/sproc/SprocThreadPrivateData.h b/src/OpenThreads/sproc/SprocThreadPrivateData.h new file mode 100755 index 000000000..5966b4527 --- /dev/null +++ b/src/OpenThreads/sproc/SprocThreadPrivateData.h @@ -0,0 +1,84 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// +// SprocThreadPrivateData.h - private data for sproc thread +// ~~~~~~~~~~~~~~~~~~~~~~~~ + +#ifndef _SPROCTHREADPRIVATEDATA_H_ +#define _SPROCTHREADPRIVATEDATA_H_ + +#include +#include +#include + +#include +#include +#include "SprocThreadPrivateActions.h" + +namespace OpenThreads { + +class SprocThreadPrivateData { + + friend class Thread; + + friend class ThreadPrivateActions; + +private: + + struct CancelFuncStruct { + + void (*routine)(void *); + void *arg; + }; + + SprocThreadPrivateData() {}; + + virtual ~SprocThreadPrivateData() {}; + + volatile unsigned int stackSize; + + volatile bool stackSizeLocked; + + volatile bool isRunning; + + Block threadStartedBlock; + + volatile bool isCanceled; + + volatile bool idSet; + + volatile bool cancelActive; + + volatile bool detached; + + volatile bool dieFlag; + + volatile Thread::ThreadPriority threadPriority; + + volatile Thread::ThreadPolicy threadPolicy; + + volatile pid_t pid; + + volatile int uniqueId; + + std::stack cancelFuncStack; + + static int nextId; + +}; + +} + +#endif // !_SPROCTHREADPRIVATEDATA_H_ diff --git a/src/OpenThreads/win32/CMakeLists.txt b/src/OpenThreads/win32/CMakeLists.txt new file mode 100644 index 000000000..a5be82fdd --- /dev/null +++ b/src/OpenThreads/win32/CMakeLists.txt @@ -0,0 +1,52 @@ +# This file should only be included when WIN32 + +SET(LIB_NAME OpenThreads) +SET(LIB_PUBLIC_HEADERS ${OpenThreads_PUBLIC_HEADERS}) + +SOURCE_GROUP("Header Files" FILES ${LIB_PUBLIC_HEADERS}) +SET_SOURCE_FILES_PROPERTIES(${LIB_PUBLIC_HEADERS} PROPERTIES HEADER_FILE_ONLY ON) + +ADD_LIBRARY(${LIB_NAME} + ${OPENTHREADS_USER_DEFINED_DYNAMIC_OR_STATIC} + ${LIB_PUBLIC_HEADERS} + HandleHolder.h + Win32BarrierPrivateData.h + WIN32Condition.cpp + Win32Condition.h + Win32ConditionPrivateData.h + Win32Mutex.cpp + Win32MutexPrivateData.h + Win32Thread.cpp + Win32ThreadBarrier.cpp + Win32ThreadPrivateData.h + ../common/Version.cpp +) + + +IF(OPENTHREADS_SONAMES) + SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES VERSION ${OPENTHREADS_VERSION} SOVERSION ${OPENTHREADS_SOVERSION}) +ENDIF(OPENTHREADS_SONAMES) + +# Since we're building different platforms binaries in +# their respective directories, we need to set the +# link directory so it can find this location. +LINK_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} +) + +IF(MSVC AND OSG_MSVC_VERSIONED_DLL) + HANDLE_MSVC_DLL(ot ${OPENTHREADS_SOVERSION}) +ENDIF(MSVC AND OSG_MSVC_VERSIONED_DLL) + +INSTALL( + TARGETS OpenThreads + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin +) +INSTALL( + FILES ${OpenThreads_PUBLIC_HEADERS} + DESTINATION include/OpenThreads +) + +#commented out# INCLUDE(ModuleInstall OPTIONAL) diff --git a/src/OpenThreads/win32/GNUmakefile b/src/OpenThreads/win32/GNUmakefile new file mode 100755 index 000000000..163b0cc8b --- /dev/null +++ b/src/OpenThreads/win32/GNUmakefile @@ -0,0 +1,38 @@ +TOPDIR = ../. +include $(TOPDIR)/Make/makedefs + +CXXFILES = \ + WIN32Condition.cpp \ + Win32Mutex.cpp \ + Win32Thread.cpp \ + Win32ThreadBarrier.cpp \ + $(NULL) + +INC += -I$(TOPDIR)/include -I. + +ifeq ($(OS),Linux) +DEF += -fPIC -DLinux -DGL_GLEXT_PROTOTYPES +LIBS += -lpthread +endif + +ifeq ($(OS),SunOS) +LIBS += -lpthread -lposix4 +endif + +ifeq ($(OS),IRIX) +LIBS += -lpthread +endif + +ifeq ($(OS),Darwin) +LIBS += -lpthread +endif + +ifeq ($(OS),MINGW) +LIBS += +DEF += -DOPENTHREADS_EXPORTS +endif + +TARGET_BASENAME = OpenThreads +LIB = $(LIB_PREFIX)$(TARGET_BASENAME) + +include $(TOPDIR)/Make/makerules diff --git a/src/OpenThreads/win32/HandleHolder.h b/src/OpenThreads/win32/HandleHolder.h new file mode 100644 index 000000000..026ab9d44 --- /dev/null +++ b/src/OpenThreads/win32/HandleHolder.h @@ -0,0 +1,89 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// +// Win32BarrierPrivateData.h - private data structure for barrier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +#ifndef _HandleHolder_H_ +#define _HandleHolder_H_ + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +/************************************************************************/ +/* Class that holds HANDLES ensuring proper destruction */ +/* It is design decision to make this class noncopyable. */ +/* It makes design much cleaner. If one wants to copy handle than one */ +/* can do hv.set(DuplicateHandle(....)) */ +/************************************************************************/ +namespace OpenThreads { + + class HandleHolder{ + private: + HANDLE _handle; + + inline void close(){ + if( _handle != INVALID_HANDLE_VALUE) CloseHandle(_handle); + _handle = INVALID_HANDLE_VALUE; + }; + + // copy constructor - disallow + HandleHolder(const HandleHolder& rhs); + + // assignment operator - disallow + HandleHolder& operator=(const HandleHolder& rhs ); + + public: + // constructor + HandleHolder() + :_handle(INVALID_HANDLE_VALUE) + {}; + + // constructor from HANDLE + explicit HandleHolder(HANDLE h) + :_handle(h) + {}; + + // destructor - CloseHandle() + ~HandleHolder() + { + close(); + }; + + // accessor + const HANDLE& get() const { + return _handle; + } + + // mutator + void set (HANDLE h) { + if( _handle != INVALID_HANDLE_VALUE ) close(); + _handle = h; + } + + operator bool (){ + return _handle != INVALID_HANDLE_VALUE && _handle != NULL; + }; + + }; + +} // namespace + + + + +#endif diff --git a/src/OpenThreads/win32/Makefile b/src/OpenThreads/win32/Makefile new file mode 100644 index 000000000..a3abb4de9 --- /dev/null +++ b/src/OpenThreads/win32/Makefile @@ -0,0 +1,18 @@ +# Makefile - OpenThreads.dsw + +.PHONY: all +all: \ + OpenThreads + +.PHONY: OpenThreads +OpenThreads: + $(MAKE) -f OpenThreads.mak + +.PHONY: clean +clean: + $(MAKE) -f OpenThreads.mak clean + +.PHONY: depends +depends: + $(MAKE) -f OpenThreads.mak depends + diff --git a/src/OpenThreads/win32/OpenThreads.dsp b/src/OpenThreads/win32/OpenThreads.dsp new file mode 100755 index 000000000..7e40f281c --- /dev/null +++ b/src/OpenThreads/win32/OpenThreads.dsp @@ -0,0 +1,231 @@ +# Microsoft Developer Studio Project File - Name="OpenThreads" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=OpenThreads - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "OpenThreads.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "OpenThreads.mak" CFG="OpenThreads - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "OpenThreads - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "OpenThreads - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "OpenThreads - Win32 Release Static" (based on "Win32 (x86) Static Library") +!MESSAGE "OpenThreads - Win32 Debug Static" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" + +!IF "$(CFG)" == "OpenThreads - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../bin/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENTHREADS_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENTHREADS_EXPORTS" /YX /FD /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /opt:ref /opt:icf /out:"$(OutDir)/OpenThreadsWin32.dll" /implib:"../lib/$(PlatformName)/OpenThreadsWin32.lib" + +!ELSEIF "$(CFG)" == "OpenThreads - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../bin/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENTHREADS_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /ZI /Od /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "OPENTHREADS_EXPORTS" /YX /FD /GZ /c +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /out:"$(OutDir)/OpenThreadsWin32d.dll" /implib:"../lib/$(PlatformName)/OpenThreadsWin32d.lib" + +!ELSEIF "$(CFG)" == "OpenThreads - Win32 Release Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release_Static" +# PROP BASE Intermediate_Dir "Release_Static" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../lib/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)_Static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +CPP=cl.exe +# ADD BASE CPP /nologo /MT /W3 /GR /GX /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "OT_LIBRARY_STATIC" /D "OPENTHREADS_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GR /GX /O2 /I "../include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "OT_LIBRARY_STATIC" /YX /FD /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../lib/$(PlatformName)/OpenThreadsWin32_s.lib" + +!ELSEIF "$(CFG)" == "OpenThreads - Win32 Debug Static" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug_Static" +# PROP BASE Intermediate_Dir "Debug_Static" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../lib/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)_Static" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +CPP=cl.exe +# ADD BASE CPP /nologo /MTd /W3 /Gm /GR /GX /Z7 /Od /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "OT_LIBRARY_STATIC" /D "OPENTHREADS_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /Z7 /Od /I "../include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "OT_LIBRARY_STATIC" /YX /FD /GZ /c +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"../lib/$(PlatformName)/OpenThreadsWin32d_s.lib" + +!ENDIF + +# Begin Target + +# Name "OpenThreads - Win32 Release" +# Name "OpenThreads - Win32 Debug" +# Name "OpenThreads - Win32 Release Static" +# Name "OpenThreads - Win32 Debug Static" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\WIN32Condition.cpp +# End Source File +# Begin Source File + +SOURCE=.\Win32Mutex.cpp +# End Source File +# Begin Source File + +SOURCE=.\Win32Thread.cpp +# End Source File +# Begin Source File + +SOURCE=.\Win32ThreadBarrier.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\include\OpenThreads\Barrier +# End Source File +# Begin Source File + +SOURCE=..\include\OpenThreads\Condition +# End Source File +# Begin Source File + +SOURCE=..\include\OpenThreads\Exports +# End Source File +# Begin Source File + +SOURCE=.\HandleHolder.h +# End Source File +# Begin Source File + +SOURCE=..\include\OpenThreads\Mutex +# End Source File +# Begin Source File + +SOURCE=..\include\OpenThreads\ScopedLock +# End Source File +# Begin Source File + +SOURCE=..\include\OpenThreads\Thread +# End Source File +# Begin Source File + +SOURCE=.\Win32BarrierPrivateData.h +# End Source File +# Begin Source File + +SOURCE=.\Win32ConditionPrivateData.h +# End Source File +# Begin Source File + +SOURCE=.\Win32MutexPrivateData.h +# End Source File +# Begin Source File + +SOURCE=.\Win32ThreadPrivateData.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/OpenThreads/win32/OpenThreads.dsw b/src/OpenThreads/win32/OpenThreads.dsw new file mode 100755 index 000000000..be8b59a23 --- /dev/null +++ b/src/OpenThreads/win32/OpenThreads.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "OpenThreads"=.\OpenThreads.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/OpenThreads/win32/OpenThreads.mak b/src/OpenThreads/win32/OpenThreads.mak new file mode 100644 index 000000000..6880e1dc1 --- /dev/null +++ b/src/OpenThreads/win32/OpenThreads.mak @@ -0,0 +1,89 @@ +# Makefile - OpenThreads.dsp + +ifndef CFG +CFG=OpenThreads - Win32 Release +endif +CC=gcc +CFLAGS= +CXX=g++ +CXXFLAGS=$(CFLAGS) +RC=windres -O COFF +ifeq "$(CFG)" "OpenThreads - Win32 Release" +CFLAGS+=-W -fexceptions -O2 -I../include -DWIN32 -DNDEBUG -D_WINDOWS -D_MBCS -D_USRDLL -DOPENTHREADS_EXPORTS +LD=g++ +LDFLAGS=-shared -Wl,--out-implib,../bin/Win32/OpenThreadsWin32.dll.a -Wl,--export-all-symbols +TARGET=../bin/Win32/OpenThreadsWin32.dll +LDFLAGS+= +LIBS+=-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 +else +ifeq "$(CFG)" "OpenThreads - Win32 Debug" +CFLAGS+=-W -fexceptions -g -O0 -I../include -DWIN32 -D_DEBUG -D_WINDOWS -D_MBCS -D_USRDLL -DOPENTHREADS_EXPORTS +LD=g++ +LDFLAGS=-shared -Wl,--out-implib,../bin/Win32/OpenThreadsWin32d.dll.a -Wl,--export-all-symbols +TARGET=../bin/Win32/OpenThreadsWin32d.dll +LDFLAGS+= +LIBS+=-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 +endif +endif + +ifndef TARGET +TARGET=OpenThreads.dll +endif + +.PHONY: all +all: $(TARGET) + +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +%.o: %.cc + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $< + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $< + +%.o: %.cxx + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ -c $< + +%.res: %.rc + $(RC) $(CPPFLAGS) -o $@ -i $< + +SOURCE_FILES= \ + WIN32Condition.cpp \ + Win32Mutex.cpp \ + Win32Thread.cpp \ + Win32ThreadBarrier.cpp + +HEADER_FILES= \ + ../include/OpenThreads/Barrier \ + ../include/OpenThreads/Condition \ + ../include/OpenThreads/Exports \ + ../include/OpenThreads/Mutex \ + ../include/OpenThreads/ScopedLock \ + ../include/OpenThreads/Thread \ + Win32BarrierPrivateData.h \ + Win32Condition.h \ + Win32ConditionPrivateData.h \ + Win32MutexPrivateData.h \ + Win32ThreadPrivateData.h \ + HandleHolder.h + +RESOURCE_FILES= + +SRCS=$(SOURCE_FILES) $(HEADER_FILES) $(RESOURCE_FILES) + +OBJS=$(patsubst %.rc,%.res,$(patsubst %.cxx,%.o,$(patsubst %.cpp,%.o,$(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(filter %.c %.cc %.cpp %.cxx %.rc,$(SRCS))))))) + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +.PHONY: clean +clean: + -rm -f $(OBJS) $(TARGET) OpenThreads.dep + +.PHONY: depends +depends: + -$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM $(filter %.c %.cc %.cpp %.cxx,$(SRCS)) > OpenThreads.dep + +-include OpenThreads.dep + diff --git a/src/OpenThreads/win32/WIN32Condition.cpp b/src/OpenThreads/win32/WIN32Condition.cpp new file mode 100644 index 000000000..4b91a33c3 --- /dev/null +++ b/src/OpenThreads/win32/WIN32Condition.cpp @@ -0,0 +1,100 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// Win32Condition.c++ - C++ Condition class built on top of posix threads. +// ~~~~~~~~~~~~~~~~~~~~ +// +#include +#include +#include "Win32ConditionPrivateData.h" + +using namespace OpenThreads; +Win32ConditionPrivateData::~Win32ConditionPrivateData() +{ +} + +//---------------------------------------------------------------------------- +// +// Description: Constructor +// +// Use: public. +// +Condition::Condition() { + Win32ConditionPrivateData *pd = + new Win32ConditionPrivateData(); + _prvData = static_cast(pd); +} +//---------------------------------------------------------------------------- +// +// Description: Destructor +// +// Use: public. +// +Condition::~Condition() { + Win32ConditionPrivateData *pd = + static_cast(_prvData); + + delete pd; +} + +//---------------------------------------------------------------------------- +// +// Description: wait on a condition +// +// Use: public. +// +int Condition::wait(Mutex *mutex) { + + Win32ConditionPrivateData *pd = + static_cast(_prvData); + + return pd->wait(*mutex, INFINITE); +} +//---------------------------------------------------------------------------- +// +// Description: wait on a condition, for a specified period of time +// +// Use: public. +// +int Condition::wait(Mutex *mutex, unsigned long ms) { + + Win32ConditionPrivateData *pd = + static_cast(_prvData); + + return pd->wait(*mutex, ms); +} +//---------------------------------------------------------------------------- +// +// Description: signal a thread to wake up. +// +// Use: public. +// +int Condition::signal() { + + Win32ConditionPrivateData *pd = + static_cast(_prvData); + return pd->signal(); +} +//---------------------------------------------------------------------------- +// +// Description: signal many threads to wake up. +// +// Use: public. +// +int Condition::broadcast() { + + Win32ConditionPrivateData *pd = + static_cast(_prvData); + return pd->broadcast(); +} diff --git a/src/OpenThreads/win32/Win32BarrierPrivateData.h b/src/OpenThreads/win32/Win32BarrierPrivateData.h new file mode 100644 index 000000000..d474e9cf4 --- /dev/null +++ b/src/OpenThreads/win32/Win32BarrierPrivateData.h @@ -0,0 +1,69 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// Win32BarrierPrivateData.h - private data structure for barrier +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +#ifndef _Win32BARRIERPRIVATEDATA_H_ +#define _Win32BARRIERPRIVATEDATA_H_ + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include +#include + +namespace OpenThreads { + +class Barrier; + +class Win32BarrierPrivateData { + friend class Barrier; +private: + Win32BarrierPrivateData() {}; + ~Win32BarrierPrivateData(); + + Condition cond; // cv for waiters at barrier + + Mutex lock; // mutex for waiters at barrier + + volatile int maxcnt; // number of threads to wait for + + volatile int cnt; // number of waiting threads + + volatile int phase; // flag to seperate two barriers + + +}; + + + + + + + +} + + + + + + + +#endif //_Win32BARRIERPRIVATEDATA_H_ + + + diff --git a/src/OpenThreads/win32/Win32Condition.h b/src/OpenThreads/win32/Win32Condition.h new file mode 100644 index 000000000..23b34207f --- /dev/null +++ b/src/OpenThreads/win32/Win32Condition.h @@ -0,0 +1,159 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +#ifndef _WIN32VODITIONPRODUCER_CONDITION +#define PRODUCER_CONDITION + +#ifdef WIN32 + +#include "Mutex.h" + +namespace OpenThreads { + +class Win32ConditionImpl +{ +public: + /// number of waiters. + long waiters_; + + Condition(long max = 0L) + { + waiters_ = 0; + sema_ = CreateSemaphore(NULL,0,0x7fffffff,NULL); + waiters_done_ = CreateEvent(NULL,FALSE,FALSE,NULL); + } + + ~Condition() + { + // CloseHandle(sema_); + // CloseHandle(waiters_done_); + } + + inline int broadcast () + { + waiters_lock_.lock(); + int have_waiters = 0; + + if (waiters_ > 0) + { + // We are broadcasting, even if there is just one waiter... + // Record the fact that we are broadcasting. This helps the + // wait() method know how to optimize itself. Be sure to + // set this with the held. + was_broadcast_ = 1; + have_waiters = 1; + } + waiters_lock_.unlock(); + + int result = 0; + if (have_waiters) + { + // Wake up all the waiters. + ReleaseSemaphore(sema_,waiters_,NULL); + WaitForSingleObject(waiters_done_,INFINITE) ; + // This is okay, even without the held because + // no other waiter threads can wake up to access it. + was_broadcast_ = 0; + } + return result; + } + + inline int wait (Mutex& external_mutex) + { + // Prevent race conditions on the count. + waiters_lock_.lock(); + waiters_++; + waiters_lock_.unlock(); + + int result = 0; + + external_mutex.unlock(); + + DWORD dwResult = WaitForSingleObject(sema_,INFINITE); + if(dwResult != WAIT_OBJECT_0) + result = (int)dwResult; + + // Reacquire lock to avoid race conditions on the count. + waiters_lock_.lock(); + + // We're ready to return, so there's one less waiter. + waiters_--; + + int last_waiter = was_broadcast_ && waiters_ == 0; + + // Release the lock so that other collaborating threads can make + // progress. + waiters_lock_.unlock(); + + if (result != -1 && last_waiter) + SetEvent(waiters_done_); + + external_mutex.lock(); + + return result; + } + + +protected: + + /// Serialize access to the waiters count. + Mutex waiters_lock_; + + /// Queue up threads waiting for the condition to become signaled. + HANDLE sema_; + /** + * An auto reset event used by the broadcast/signal thread to wait + * for the waiting thread(s) to wake up and get a chance at the + * semaphore. + */ + HANDLE waiters_done_; + + /// Keeps track of whether we were broadcasting or just signaling. + size_t was_broadcast_; + +}; +#else +#include + +namespace Producer { + +class PR_EXPORT Condition +{ +public: + /// number of waiters. + Condition(long max) + { + pthread_cond_init( &_cond, 0L ); + } + + ~Condition() + { + } + + inline int broadcast () + { + return pthread_cond_broadcast(&_cond); + } + + inline int wait (Mutex& external_mutex) + { + return pthread_cond_wait(&_cond); + } + + +protected: + pthread_cond_t _cond; +}; +#endif +} +#endif \ No newline at end of file diff --git a/src/OpenThreads/win32/Win32ConditionPrivateData.h b/src/OpenThreads/win32/Win32ConditionPrivateData.h new file mode 100644 index 000000000..0c2ec6bf0 --- /dev/null +++ b/src/OpenThreads/win32/Win32ConditionPrivateData.h @@ -0,0 +1,163 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// +// WIN32ConditionPrivateData.h - Private data structure for Condition +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +#ifndef _WIN32CONDITIONPRIVATEDATA_H_ +#define _WIN32CONDITIONPRIVATEDATA_H_ + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include + +#include "Win32ThreadPrivateData.h" +#include "HandleHolder.h" + +#define InterlockedGet(x) InterlockedExchangeAdd(x,0) + +namespace OpenThreads { + +class Condition; + +class Win32ConditionPrivateData { +public: + friend class Condition; + /// number of waiters. + long waiters_; + + Win32ConditionPrivateData () + :waiters_(0), + sema_(CreateSemaphore(NULL,0,0x7fffffff,NULL)), + waiters_done_(CreateEvent(NULL,FALSE,FALSE,NULL)) + { + } + + ~Win32ConditionPrivateData (); + + inline int broadcast () + { + int have_waiters = 0; + long w = InterlockedGet(&waiters_); + + if (w > 0) + { + // we are broadcasting. + was_broadcast_ = 1; + have_waiters = 1; + } + + int result = 0; + if (have_waiters) + { + // Wake up all the waiters. + ReleaseSemaphore(sema_.get(),waiters_,NULL); + + cooperativeWait(waiters_done_.get(), INFINITE); + + //end of broadcasting + was_broadcast_ = 0; + } + return result; + } + + inline int signal() + { + long w = InterlockedGet(&waiters_); + int have_waiters = w > 0; + + int result = 0; + + if (have_waiters) + { + if( !ReleaseSemaphore(sema_.get(),1,NULL) ) + result = -1; + } + return result; + } + + inline int wait (Mutex& external_mutex, long timeout_ms) + { + + // Prevent race conditions on the count. + InterlockedIncrement(&waiters_); + + int result = 0; + + ReverseScopedLock lock(external_mutex); + + // wait in timeslices, giving testCancel() a change to + // exit the thread if requested. + try { + DWORD dwResult = cooperativeWait(sema_.get(), timeout_ms); + if(dwResult != WAIT_OBJECT_0) + result = (int)dwResult; + } + catch(...){ + // thread is canceled in cooperative wait , do cleanup + InterlockedDecrement(&waiters_); + long w = InterlockedGet(&waiters_); + int last_waiter = was_broadcast_ && w == 0; + + if (last_waiter) SetEvent(waiters_done_.get()); + // rethrow + throw; + } + + + // We're ready to return, so there's one less waiter. + InterlockedDecrement(&waiters_); + long w = InterlockedGet(&waiters_); + int last_waiter = was_broadcast_ && w == 0; + + if (result != -1 && last_waiter) + SetEvent(waiters_done_.get()); + + return result; + } + +protected: + + /// Serialize access to the waiters count. + /// Mutex waiters_lock_; + /// Queue up threads waiting for the condition to become signaled. + HandleHolder sema_; + /** + * An auto reset event used by the broadcast/signal thread to wait + * for the waiting thread(s) to wake up and get a chance at the + * semaphore. + */ + HandleHolder waiters_done_; + /// Keeps track of whether we were broadcasting or just signaling. + size_t was_broadcast_; +}; + +#undef InterlockedGet + +} + + + + + + + +#endif // !_WIN32CONDITIONPRIVATEDATA_H_ + + + diff --git a/src/OpenThreads/win32/Win32Mutex.cpp b/src/OpenThreads/win32/Win32Mutex.cpp new file mode 100644 index 000000000..7fa75b607 --- /dev/null +++ b/src/OpenThreads/win32/Win32Mutex.cpp @@ -0,0 +1,222 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// +// Win32Mutex.c++ - C++ Mutex class . +// The idea for it is borrowed from SGI STL +// It looks like it's hard to use win32 CRITICALL_SECTIONS withour introducing race +// conditions on InitializeCriticalSection() . So we use spin mutex here. +// ~~~~~~~~~~~~~~~~ +// + +#include +#include "Win32MutexPrivateData.h" +using namespace OpenThreads; + +Win32MutexPrivateData::Win32MutexPrivateData() +{ +#ifdef USE_CRITICAL_SECTION + InitializeCriticalSection( &_cs ); +#else + mutex = 0; +#endif +} +Win32MutexPrivateData::~Win32MutexPrivateData() +{ +#ifdef USE_CRITICAL_SECTION + DeleteCriticalSection( &_cs ); +#endif +} + + +#ifndef USE_CRITICAL_SECTION + +template +struct WIN32MutexSpin { + + enum { __low_max = 30, __high_max = 1000 }; + // Low if we suspect uniprocessor, high for multiprocessor. + static unsigned __max; + static unsigned __last; +}; + +template +unsigned WIN32MutexSpin ::__max = WIN32MutexSpin ::__low_max; + +template +unsigned WIN32MutexSpin ::__last = 0; + + + +static void _S_nsec_sleep(int __log_nsec) { + + if (__log_nsec <= 20) { + SwitchToThread(); //Sleep(0); // adegli replaced it Sleep by SwitchToThread + } else { + Sleep(1 << (__log_nsec - 20)); + } +} + + +#if defined(_MSC_VER) && _MSC_VER <= 1300 + template WIN32MutexSpin <0>; +#endif + +#endif // USE_CRITICAL_SECTION + +//---------------------------------------------------------------------------- +// +// Description: Constructor +// +// Use: public. +// +Mutex::Mutex() { + Win32MutexPrivateData *pd = new Win32MutexPrivateData(); + _prvData = static_cast(pd); +} + +//---------------------------------------------------------------------------- +// +// Description: Destructor +// +// Use: public. +// +Mutex::~Mutex() { + unlock(); + delete static_cast(_prvData); +} +//---------------------------------------------------------------------------- +// +// Description: lock the mutex +// +// Use: public. +// +int Mutex::lock() { + Win32MutexPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_CRITICAL_SECTION + + // Block until we can take this lock. + EnterCriticalSection( &(pd->_cs) ); + + return 0; + +#else + + volatile unsigned long* lock = &pd->mutex; + // InterlockedExchange returns old value + // if old_value == 0 mutex wasn't locked , now it is + if( !InterlockedExchange((long*)lock, 1L)) { + return 0; + } + + unsigned my_spin_max = WIN32MutexSpin<0>::__max; + unsigned my_last_spins = WIN32MutexSpin<0>::__last; + volatile unsigned junk = 17; + unsigned i; + + for (i = 0; i < my_spin_max; i++) { + if (i < my_last_spins/2 || *lock) { + junk *= junk; junk *= junk; + junk *= junk; junk *= junk; + continue; + } + + if (!InterlockedExchange((long*)lock, 1L)) { + // got it! + // Spinning worked. Thus we're probably not being scheduled + // against the other process with which we were contending. + // Thus it makes sense to spin longer the next time. + WIN32MutexSpin<0>::__last = i; + WIN32MutexSpin<0>::__max = WIN32MutexSpin<0>::__high_max; + return 0; + } + } + // We are probably being scheduled against the other process. Sleep. + WIN32MutexSpin<0>::__max = WIN32MutexSpin<0>::__low_max; + for (i = 0 ;; ++i) { + int __log_nsec = i + 6; + if (__log_nsec > 27) __log_nsec = 27; + if (!InterlockedExchange((long*)lock, 1L)) { + return 0; + } + _S_nsec_sleep(__log_nsec); + } + return -1; + +#endif // USE_CRITICAL_SECTION +} + +//---------------------------------------------------------------------------- +// +// Description: unlock the mutex +// +// Use: public. +// +int Mutex::unlock() { + Win32MutexPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_CRITICAL_SECTION + + // Release this lock. CRITICAL_SECTION is nested, thus + // unlock() calls must be paired with lock() calls. + LeaveCriticalSection( &(pd->_cs) ); + + return 0; + +#else + + volatile unsigned long* lock = &pd->mutex; + *lock = 0; + // This is not sufficient on many multiprocessors, since + // writes to protected variables and the lock may be reordered. + return 0; + +#endif // USE_CRITICAL_SECTION +} + +//---------------------------------------------------------------------------- +// +// Description: test if the mutex may be locked +// +// Use: public. +// +int Mutex::trylock() { + Win32MutexPrivateData *pd = + static_cast(_prvData); + +#ifdef USE_CRITICAL_SECTION + + // Take the lock if we can; regardless don't block. + // 'result' is FALSE if we took the lock or already held + // it amd TRUE if another thread already owns the lock. + BOOL result = TryEnterCriticalSection( &(pd->_cs) ); + + return( (result==TRUE) ? 0 : 1 ); + +#else + + volatile unsigned long* lock = &pd->mutex; + + if( !InterlockedExchange((long*)lock, 1L)) { + return 1; // TRUE + } + + return 0; // FALSE + +#endif // USE_CRITICAL_SECTION +} + diff --git a/src/OpenThreads/win32/Win32MutexPrivateData.h b/src/OpenThreads/win32/Win32MutexPrivateData.h new file mode 100644 index 000000000..dd196dcc7 --- /dev/null +++ b/src/OpenThreads/win32/Win32MutexPrivateData.h @@ -0,0 +1,55 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// Win32MutexPrivateData.h - Private data structure for Mutex +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// + +#ifndef _Win32MUTEXPRIVATEDATA_H_ +#define _Win32MUTEXPRIVATEDATA_H_ + + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0400 // was missing : adegli +#include +#endif +namespace OpenThreads { + +class Win32MutexPrivateData { + friend class Mutex; + friend class Condition; + +private: + + Win32MutexPrivateData(); + + ~Win32MutexPrivateData(); +#define USE_CRITICAL_SECTION +#ifdef USE_CRITICAL_SECTION + CRITICAL_SECTION _cs; +#else + volatile unsigned long mutex; +#endif + +}; + +} + +#endif // !_Win32MUTEXPRIVATEDATA_H_ + + + + + diff --git a/src/OpenThreads/win32/Win32Thread.cpp b/src/OpenThreads/win32/Win32Thread.cpp new file mode 100644 index 000000000..dc414aa3a --- /dev/null +++ b/src/OpenThreads/win32/Win32Thread.cpp @@ -0,0 +1,682 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Win32Thread.c++ +// ~~~~~~~~~~~ +#include +#include +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER < 1300) +#ifdef __SGI_STL +using std::size_t; +#endif +#else +using std::size_t; +#endif + +#if defined(_MSC_VER) + #pragma warning( disable : 4996 ) +#endif + +#include "Win32ThreadPrivateData.h" + +struct Win32ThreadCanceled{}; + +using namespace OpenThreads; + +DWORD OpenThreads::cooperativeWait(HANDLE waitHandle, unsigned long timeout){ + Thread* current = Thread::CurrentThread(); + DWORD dwResult ; + if(current) + { + HANDLE cancelHandle = static_cast(current->getImplementation())->cancelEvent.get(); + HANDLE handleSet[2] = {waitHandle, cancelHandle}; + + dwResult = WaitForMultipleObjects(2,handleSet,FALSE,timeout); + if(dwResult == WAIT_OBJECT_0 + 1 ) throw Win32ThreadCanceled(); + } + else + { + dwResult = WaitForSingleObject(waitHandle,timeout); + } + + return dwResult; +} + +Win32ThreadPrivateData::TlsHolder Win32ThreadPrivateData::TLS; + +Win32ThreadPrivateData::~Win32ThreadPrivateData() +{ +} + +const std::string OPENTHREAD_VERSION_STRING = "OpenThread v1.2preAlpha, WindowThreads (Public Implementation)"; + + +//----------------------------------------------------------------------------- +// Initialize thread master priority level +// +Thread::ThreadPriority Thread::s_masterThreadPriority = Thread::THREAD_PRIORITY_DEFAULT; + +bool Thread::s_isInitialized = false; +//----------------------------------------------------------------------------- +// Class to support some static methods necessary for pthread's to work +// correctly. +// +namespace OpenThreads { + + class ThreadPrivateActions { + //------------------------------------------------------------------------- + // We're friendly to Thread, so it can issue the methods. + // + friend class Thread; + private: + + //------------------------------------------------------------------------- + // Win32Threads standard start routine. + // + static unsigned int __stdcall StartThread(void *data) { + + Thread *thread = static_cast(data); + + Win32ThreadPrivateData *pd = + static_cast(thread->_prvData); + + if (thread->_prvData==0) return 0; + + TlsSetValue(Win32ThreadPrivateData::TLS.ID ,data); + //--------------------------------------------------------------------- + // Set the proper scheduling priorities + // + SetThreadSchedulingParams(thread); + + pd->isRunning = true; + + // release the thread that created this thread. + pd->threadStartedBlock.release(); + + try{ + thread->run(); + } + catch(Win32ThreadCanceled&) + { + // thread is canceled do cleanup + try { + thread->cancelCleanup(); + } catch(...) { } + } + catch(...) + { + // abnormal termination but must be caught in win32 anyway + } + + pd->isRunning = false; + + return 0; + }; + + //------------------------------------------------------------------------- + // Print information related to thread schduling parameters. + // + static void PrintThreadSchedulingInfo(Thread *thread) { + Win32ThreadPrivateData *pd = + static_cast(thread->_prvData); + + std::cout<<"Thread "<< thread <<" priority : "; + + switch(thread->getSchedulePriority()) { + case Thread::THREAD_PRIORITY_MAX: + std::cout<<"MAXIMAL"<(thread->_prvData); + + int prio = THREAD_PRIORITY_NORMAL; + + switch(thread->getSchedulePriority()) { + case Thread::THREAD_PRIORITY_MAX: + prio = THREAD_PRIORITY_HIGHEST; + break; + case Thread::THREAD_PRIORITY_HIGH: + prio = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case Thread::THREAD_PRIORITY_NOMINAL: + prio = THREAD_PRIORITY_NORMAL; + break; + case Thread::THREAD_PRIORITY_LOW: + prio = THREAD_PRIORITY_BELOW_NORMAL; + break; + case Thread::THREAD_PRIORITY_MIN: + prio = THREAD_PRIORITY_IDLE; + break; + } + + int status = SetThreadPriority( pd->tid.get(), prio); + + if(getenv("OUTPUT_THREADLIB_SCHEDULING_INFO") != 0) + PrintThreadSchedulingInfo(thread); + + return status!=0; + }; + }; +}; + +Thread* Thread::CurrentThread() +{ + return (Thread* )TlsGetValue(Win32ThreadPrivateData::TLS.ID); +}; + +//---------------------------------------------------------------------------- +// +// Description: Set the concurrency level (no-op) +// +// Use static public +// +int Thread::SetConcurrency(int) { + return -1; +}; + +//---------------------------------------------------------------------------- +// +// Description: Get the concurrency level +// +// Use static public +// +int Thread::GetConcurrency() { + return -1; +}; + +//---------------------------------------------------------------------------- +// +// Description: Constructor +// +// Use: public. +// +Thread::Thread() { + + // there's no need for this + // if(!s_isInitialized) Init(); + + Win32ThreadPrivateData *pd = new Win32ThreadPrivateData(); + + pd->stackSize = 0; + pd->isRunning = false; + pd->cancelMode = 0; + pd->uniqueId = 0; + pd->threadPriority = Thread::THREAD_PRIORITY_DEFAULT; + pd->threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT; + pd->detached = false; + pd->cancelEvent.set(CreateEvent(NULL,TRUE,FALSE,NULL)); + + _prvData = static_cast(pd); +} + + +//---------------------------------------------------------------------------- +// +// Description: Destructor +// +// Use: public. +// +Thread::~Thread() +{ + Win32ThreadPrivateData *pd = static_cast(_prvData); + + if(pd->isRunning) + { + std::cout<<"Error: Thread "<cancelMode = 0; + cancel(); + } + + delete pd; + + _prvData = 0; +} +//----------------------------------------------------------------------------- +// +// Description: Initialize Threading +// +// Use: public. +// +void Thread::Init() { +// if(s_isInitialized) return; +// s_masterThreadPriority = Thread::THREAD_PRIORITY_DEFAULT; + s_isInitialized = true; +} + +//----------------------------------------------------------------------------- +// +// Description: Get a unique identifier for this thread. +// +// Use: public +// +int Thread::getThreadId() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + return pd->uniqueId; +} +//----------------------------------------------------------------------------- +// +// Description: Get the thread's process id +// +// Use: public +// +size_t Thread::getProcessId() { + + return (size_t) GetCurrentProcessId(); + +} +//----------------------------------------------------------------------------- +// +// Description: Determine if the thread is running +// +// Use: public +// +bool Thread::isRunning() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + return pd->isRunning; +} +//----------------------------------------------------------------------------- +// +// Description: Start the thread. +// +// Use: public +// +int Thread::start() { + + Win32ThreadPrivateData *pd = static_cast (_prvData); + //------------------------------------------------------------------------- + // Prohibit the stack size from being changed. + // (bb 5/13/2005) it actually doesn't matter. + // 1) usually setStackSize()/start() sequence is serialized. + // 2) if not than we're in trouble anyway - nothing is protected + // pd->stackSizeLocked = true; + unsigned int ID; + + pd->threadStartedBlock.reset(); + + pd->tid.set( (void*)_beginthreadex(NULL,pd->stackSize,ThreadPrivateActions::StartThread,static_cast(this),0,&ID)); + + pd->uniqueId = (int)ID; + + // wait till the thread has actually started. + pd->threadStartedBlock.block(); + + if(!pd->tid) { + return -1; + } + + return 0; + +} + +int Thread::startThread() +{ + if (_prvData) return start(); + else return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Join the thread. +// +// Use: public +// +int Thread::join() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + if( pd->detached ) + return -1; // cannot wait for detached ; + + if( WaitForSingleObject(pd->tid.get(),INFINITE) != WAIT_OBJECT_0) + return -1 ; + + return 0; +} + + + +int Thread::detach() +{ + Win32ThreadPrivateData *pd = static_cast (_prvData); + pd->detached = true; + return 0; +} + + +//----------------------------------------------------------------------------- +// +// Description: Cancel the thread. +// +// Use: public +// +int Thread::cancel() +{ + Win32ThreadPrivateData *pd = static_cast (_prvData); + + if (pd->isRunning) + { + if( pd->cancelMode == 2 ) + return -1; + + // signal all interested parties that we are going to exit + SetEvent(pd->cancelEvent.get()); + + // cancelMode == 1 (asynch)-> kill em + // cancelMode == 0 (deffered) -> wait a little then kill em + + // if( (pd->cancelMode == 1) || (WaitForSingleObject(pd->tid,INFINITE)!=WAIT_OBJECT_0) ) + if( pd->cancelMode == 1 ) + { + // did not terminate cleanly force termination + pd->isRunning = false; + return TerminateThread(pd->tid.get(),(DWORD)-1); + } + } + + return 0; +} + + + +int Thread::testCancel() +{ + Win32ThreadPrivateData *pd = static_cast (_prvData); + + if(WaitForSingleObject(pd->cancelEvent.get(),0) != WAIT_OBJECT_0) return 0; + + if(pd->cancelMode == 2) + return 0; + + DWORD curr = GetCurrentThreadId(); + + if( pd->uniqueId != (int)curr ) + return -1; + +// pd->isRunning = false; +// ExitThread(0); + throw Win32ThreadCanceled(); + + return 0; + +} + + + +//----------------------------------------------------------------------------- +// +// Description: Disable cancelibility +// +// Use: public +// +int Thread::setCancelModeDisable() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + pd->cancelMode = 2; + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel immediately +// +// Use: public +// +int Thread::setCancelModeAsynchronous() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + pd->cancelMode = 1; + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: set the thread to cancel at the next convenient point. +// +// Use: public +// +int Thread::setCancelModeDeferred() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + pd->cancelMode = 0; + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's schedule priority (if able) +// +// Use: public +// +int Thread::setSchedulePriority(ThreadPriority priority) { + Win32ThreadPrivateData *pd = static_cast (_prvData); + + pd->threadPriority = priority; + + if(pd->isRunning) + return ThreadPrivateActions::SetThreadSchedulingParams(this); + else + return 0; +} + + +//----------------------------------------------------------------------------- +// +// Description: Get the thread's schedule priority (if able) +// +// Use: public +// +int Thread::getSchedulePriority() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + return pd->threadPriority; +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::setSchedulePolicy(ThreadPolicy policy) { + Win32ThreadPrivateData *pd = static_cast (_prvData); + + pd->threadPolicy = policy; + + if(pd->isRunning) + return ThreadPrivateActions::SetThreadSchedulingParams(this); + else + return 0; +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's scheduling policy (if able) +// +// Use: public +// +int Thread::getSchedulePolicy() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + return pd->threadPolicy; +} + +//----------------------------------------------------------------------------- +// +// Description: Set the thread's desired stack size +// +// Use: public +// +int Thread::setStackSize(size_t stackSize) { + Win32ThreadPrivateData *pd = static_cast (_prvData); + if(pd->isRunning) return 13; // cannot set stack size of running thread return EACESS + pd->stackSize = stackSize; + return 0; +} +//----------------------------------------------------------------------------- +// +// Description: Get the thread's stack size. +// +// Use: public +// +size_t Thread::getStackSize() { + Win32ThreadPrivateData *pd = static_cast (_prvData); + return pd->stackSize; +} + +//----------------------------------------------------------------------------- +// +// Description: set processor affinity for the thread +// +// Use: public +// +int Thread::setProcessorAffinity( unsigned int cpunum ) +{ + Win32ThreadPrivateData *pd = static_cast (_prvData); + DWORD affinityMask = 0x1 << cpunum ; // thread affinity mask + DWORD_PTR res = + SetThreadAffinityMask + ( + pd->tid.get(), // handle to thread + affinityMask // thread affinity mask + ); +/* + This one is funny. + This is "non-mandatory" affinity , windows will try to use dwIdealProcessor + whenever possible ( when Bill's account is over 50B, maybe :-) ). + + DWORD SetThreadIdealProcessor( + HANDLE hThread, // handle to the thread + DWORD dwIdealProcessor // ideal processor number + ); +*/ + // return value 1 means call is ignored ( 9x/ME/SE ) + if( res == 1 ) return -1; + // return value 0 is failure + return (res == 0) ? GetLastError() : 0 ; +} + +//----------------------------------------------------------------------------- +// +// Description: Print the thread's scheduling information to stdout. +// +// Use: public +// +void Thread::printSchedulingInfo() { + ThreadPrivateActions::PrintThreadSchedulingInfo(this); +} + + +//----------------------------------------------------------------------------- +// +// Description: Yield the processor +// +// Use: protected +// +#if _WIN32_WINNT < 0x0400 // simulate +int SwitchToThread (void) +{ + ::Sleep(10); + return 0; +}; +#endif + +int Thread::YieldCurrentThread() +{ + return SwitchToThread(); +} + +int Thread::microSleep(unsigned int microsec) +{ +#if _WIN32_WINNT < 0x0400 // simulate + ::Sleep(microsec/1000); + return 0; +#else + HandleHolder sleepTimer(CreateWaitableTimer(NULL, TRUE, NULL)); + + if( !sleepTimer ) + return -1; + + LARGE_INTEGER t; + + t.QuadPart= -(LONGLONG)microsec*10; // in 100ns units + // negative sign means relative, + + if (!SetWaitableTimer(sleepTimer.get(), &t, 0, NULL, NULL, 0)) + { + return -1; + } + + // Wait for the timer. + if (WaitForSingleObject(sleepTimer.get(), INFINITE) != WAIT_OBJECT_0) + { + return -1; + } + return 0; +#endif +} + + +//----------------------------------------------------------------------------- +// +// Description: Get the number of processors +// +int OpenThreads::GetNumberOfProcessors() +{ + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + + return sysInfo.dwNumberOfProcessors; +} + +int OpenThreads::SetProcessorAffinityOfCurrentThread(unsigned int cpunum) +{ + if (cpunum<0) return -1; + + Thread::Init(); + + Thread* thread = Thread::CurrentThread(); + if (thread) + { + return thread->setProcessorAffinity(cpunum); + } + else + { + // non op right now, needs implementation. + return -1; + } +} diff --git a/src/OpenThreads/win32/Win32ThreadBarrier.cpp b/src/OpenThreads/win32/Win32ThreadBarrier.cpp new file mode 100644 index 000000000..dbaa4cb07 --- /dev/null +++ b/src/OpenThreads/win32/Win32ThreadBarrier.cpp @@ -0,0 +1,149 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// Win32Barrier.c++ - C++ Barrier class built on top of POSIX threads. +// ~~~~~~~~~~~~~~~~~~ +// + +#include +#include +#include +#include "Win32BarrierPrivateData.h" +using namespace OpenThreads; + +// so compiler can place it somewhere +Win32BarrierPrivateData::~Win32BarrierPrivateData() +{ +}; + +//---------------------------------------------------------------------------- +// +// Description: Constructor +// +// Use: public. +// +Barrier::Barrier(int numThreads) { + Win32BarrierPrivateData *pd = new Win32BarrierPrivateData(); + pd->cnt = 0; + pd->phase = 0; + pd->maxcnt = numThreads; + _valid = true; + _prvData = static_cast(pd); +} +//---------------------------------------------------------------------------- +// +// Description: Destructor +// +// Use: public. +// +Barrier::~Barrier() { + Win32BarrierPrivateData *pd = + static_cast(_prvData); + delete pd; +} +//---------------------------------------------------------------------------- +// +// Description: Reset the barrier to its original state +// +// Use: public. +// +void Barrier::reset() { + Win32BarrierPrivateData *pd = + static_cast(_prvData); + pd->cnt = 0; + pd->phase = 0; +} +//---------------------------------------------------------------------------- +// +// Description: Block until numThreads threads have entered the barrier. +// +// Use: public. +// +void Barrier::block(unsigned int numThreads) { + + Win32BarrierPrivateData *pd = + static_cast(_prvData); + + if(numThreads != 0) pd->maxcnt = numThreads; + int my_phase; + + ScopedLock lock(pd->lock); + if( _valid ) + { + my_phase = pd->phase; + ++pd->cnt; + + if (pd->cnt == pd->maxcnt) { // I am the last one + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pd->cond.broadcast(); + }else{ + while (pd->phase == my_phase ) { + pd->cond.wait(&pd->lock); + } + } + } +} + +void Barrier::invalidate() +{ + Win32BarrierPrivateData *pd = + static_cast(_prvData); + + pd->lock.lock(); + _valid = false; + pd->lock.unlock(); + release(); +} + + +//---------------------------------------------------------------------------- +// +// Description: Release the barrier, now. +// +// Use: public. +// +void Barrier::release() { + + Win32BarrierPrivateData *pd = + static_cast(_prvData); + + int my_phase; + + ScopedLock lock(pd->lock); + my_phase = pd->phase; + + pd->cnt = 0; // reset for next use + pd->phase = 1 - my_phase; // toggle phase + pd->cond.broadcast(); + +} + +//---------------------------------------------------------------------------- +// +// Description: Return the number of threads currently blocked in the barrier +// +// Use: public +// +int Barrier::numThreadsCurrentlyBlocked() { + + Win32BarrierPrivateData *pd = + static_cast(_prvData); + + int numBlocked = -1; + ScopedLock lock(pd->lock); + numBlocked = pd->cnt; + return numBlocked; + +} diff --git a/src/OpenThreads/win32/Win32ThreadPrivateData.h b/src/OpenThreads/win32/Win32ThreadPrivateData.h new file mode 100644 index 000000000..b59d2426a --- /dev/null +++ b/src/OpenThreads/win32/Win32ThreadPrivateData.h @@ -0,0 +1,95 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2002 - 2007 The Open Thread Group + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + +// +// Win32PrivateData.h - Private data structure for Thread +// ~~~~~~~~~~~~~~~~~~~~~ +#ifndef _Win32PRIVATEDATA_H_ +#define _Win32PRIVATEDATA_H_ + +#ifndef _WINDOWS_ +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0400 +#include +#endif + +#include +#include +#include "HandleHolder.h" + +namespace OpenThreads { + + class Win32ThreadPrivateData { + //------------------------------------------------------------------------- + // We're friendly to Thread, so it can use our data. + // + friend class Thread; + //------------------------------------------------------------------------- + // We're friendly to Win32PrivateActions, so it can get at some + // variables. + // + friend class ThreadPrivateActions; + +private: + + Win32ThreadPrivateData() {}; + ~Win32ThreadPrivateData(); + + size_t stackSize; + bool isRunning; + + Block threadStartedBlock; + + int cancelMode; // 0 - deffered (default) 1-asynch 2-disabled + + bool detached; + + Thread::ThreadPriority threadPriority; + + Thread::ThreadPolicy threadPolicy; + + HandleHolder tid; + + int uniqueId; + +public: + + HandleHolder cancelEvent; + + struct TlsHolder{ // thread local storage slot + DWORD ID; + TlsHolder(): ID(TlsAlloc()){ + } + ~TlsHolder(){ + TlsFree(ID); + } + }; + + static TlsHolder TLS; + +}; + +DWORD cooperativeWait(HANDLE waitHandle, unsigned long timeout); + + +} + + + + + + +#endif // !_PTHREADPRIVATEDATA_H_ + + +