/* -*-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 #include namespace OpenThreads { /** * Get the number of processors. * * Note, systems where no support exists for querying the number of processors, 1 is returned. * */ extern OPENTHREAD_EXPORT_DIRECTIVE int GetNumberOfProcessors(); /** * Set the processor affinity of current thread. */ extern OPENTHREAD_EXPORT_DIRECTIVE int SetProcessorAffinityOfCurrentThread(const Affinity& affinity); /** * @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 careful * to manage the thread priorities, a priority inversion deadlock can * easily occur (Although the OpenThreads::Mutex & OpenThreads::Barrier * constructs have been designed with this scenario in mind). Unless * you have explicit need to set the schedule priorities for a given * task, it is best to leave them alone. * * @note some implementations (notably LinuxThreads and IRIX Sprocs) * only allow you to decrease thread priorities dynamically. Thus, * a lower priority thread will not allow it's priority to be raised * on the fly. * * @note setting 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 setting 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 setting 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 setting 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 cancellation altogether. Thread::cancel() has no effect. * * @return 0 if normal, -1 if errno set, errno code otherwise. */ int setCancelModeDisable(); /** * Mark the thread to cancel asynchronously 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 * cancellation 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; }; /** Set the Thread's processor affinity to all, a single CPU or multiple CPU's * This call must be made before * start() or startThread() and has no effect after the thread * has been running. Returns 0 on success, implementation's * error on failure, or -1 if ignored. */ int setProcessorAffinity( const Affinity& affinity); /** microSleep method, equivalent 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 * success, 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_