// // ZoneMinder Thread Class Interface, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program 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 // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // #ifndef ZM_THREAD_H #define ZM_THREAD_H #include #include #include #ifdef HAVE_SYS_SYSCALL_H #include #endif // HAVE_SYS_SYSCALL_H #include "zm_exception.h" #include "zm_utils.h" #ifdef __FreeBSD__ #include #endif class ThreadException : public Exception { private: #ifndef SOLARIS pid_t pid() { pid_t tid; #ifdef __FreeBSD__ long lwpid; thr_self(&lwpid); tid = lwpid; #else #ifdef __FreeBSD_kernel__ if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id # else tid=syscall(SYS_gettid); #endif #endif return tid; } #else pthread_t pid() { return( pthread_self() ); } #endif public: ThreadException( const std::string &message ) : Exception( stringtf( "(%d) "+message, (long int)pid() ) ) { } }; class Mutex { friend class Condition; private: pthread_mutex_t mMutex; public: Mutex(); ~Mutex(); private: pthread_mutex_t *getMutex() { return( &mMutex ); } public: void lock(); void lock( int secs ); void lock( double secs ); void unlock(); bool locked(); }; class ScopedMutex { private: Mutex &mMutex; public: ScopedMutex( Mutex &mutex ) : mMutex( mutex ) { mMutex.lock(); } ~ScopedMutex() { mMutex.unlock(); } private: ScopedMutex( const ScopedMutex & ); }; class Condition { private: Mutex &mMutex; pthread_cond_t mCondition; public: Condition( Mutex &mutex ); ~Condition(); void wait(); bool wait( int secs ); bool wait( double secs ); void signal(); void broadcast(); }; class Semaphore : public Condition { private: Mutex mMutex; public: Semaphore() : Condition( mMutex ) { } void wait() { mMutex.lock(); Condition::wait(); mMutex.unlock(); } bool wait( int secs ) { mMutex.lock(); bool result = Condition::wait( secs ); mMutex.unlock(); return( result ); } bool wait( double secs ) { mMutex.lock(); bool result = Condition::wait( secs ); mMutex.unlock(); return( result ); } void signal() { mMutex.lock(); Condition::signal(); mMutex.unlock(); } void broadcast() { mMutex.lock(); Condition::broadcast(); mMutex.unlock(); } }; template class ThreadData { private: T mValue; mutable bool mChanged; mutable Mutex mMutex; mutable Condition mCondition; public: __attribute__((used)) ThreadData() : mCondition( mMutex ) { } __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) { } //~ThreadData() {} __attribute__((used)) operator T() const { return( getValue() ); } __attribute__((used)) const T operator=( const T value ) { return( setValue( value ) ); } __attribute__((used)) const T getValueImmediate() const { return( mValue ); } __attribute__((used)) T setValueImmediate( const T value ) { return( mValue = value ); } __attribute__((used)) const T getValue() const; __attribute__((used)) T setValue( const T value ); __attribute__((used)) const T getUpdatedValue() const; __attribute__((used)) const T getUpdatedValue( double secs ) const; __attribute__((used)) const T getUpdatedValue( int secs ) const; __attribute__((used)) void updateValueSignal( const T value ); __attribute__((used)) void updateValueBroadcast( const T value ); }; class Thread { public: typedef void *(*ThreadFunc)( void * ); protected: pthread_t mThread; Mutex mThreadMutex; Condition mThreadCondition; #ifndef SOLARIS pid_t mPid; #else pthread_t mPid; #endif bool mStarted; bool mRunning; int status; // Used in various functions to get around return a local variable protected: Thread(); virtual ~Thread(); #ifndef SOLARIS pid_t id() const { pid_t tid; #ifdef __FreeBSD__ long lwpid; thr_self(&lwpid); tid = lwpid; #else #ifdef __FreeBSD_kernel__ if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id #else tid=syscall(SYS_gettid); #endif #endif return tid; } #else pthread_t id() const { return( pthread_self() ); } #endif void exit( int p_status = 0 ) { //INFO( "Exiting" ); pthread_exit( (void *)&p_status ); } static void *mThreadFunc( void *arg ); public: virtual int run() = 0; void start(); void join(); void kill( int signal ); bool isThread() { return( mPid > -1 && pthread_equal( pthread_self(), mThread ) ); } bool isStarted() const { return( mStarted ); } bool isRunning() const { return( mRunning ); } }; #endif // ZM_THREAD_H