zoneminder/src/zm_thread.h

267 lines
5.5 KiB
C++

//
// 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 <unistd.h>
#include <pthread.h>
#include <unistd.h>
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif // HAVE_SYS_SYSCALL_H
#include "zm_exception.h"
#include "zm_utils.h"
#ifdef __FreeBSD__
#include <sys/thr.h>
#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:
explicit ThreadException( const std::string &message ) : Exception( stringtf("(%d) ", (long int)pid())+message ) {
}
};
class Mutex {
friend class Condition;
private:
pthread_mutex_t mMutex;
public:
Mutex();
~Mutex();
private:
pthread_mutex_t *getMutex() {
return &mMutex;
}
public:
int trylock();
void lock();
void lock( int secs );
void lock( double secs );
void unlock();
bool locked();
};
class RecursiveMutex : public Mutex {
private:
pthread_mutex_t mMutex;
public:
RecursiveMutex();
};
class ScopedMutex {
private:
Mutex &mMutex;
public:
explicit ScopedMutex( Mutex &mutex ) : mMutex( mutex ) {
mMutex.lock();
}
~ScopedMutex() {
mMutex.unlock();
}
private:
ScopedMutex( const ScopedMutex & );
};
class Condition {
private:
Mutex &mMutex;
pthread_cond_t mCondition;
public:
explicit 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 T> class ThreadData {
private:
T mValue;
mutable bool mChanged;
mutable Mutex mMutex;
mutable Condition mCondition;
public:
__attribute__((used)) ThreadData() : mValue(0), mCondition( mMutex ) {
mChanged = false;
}
explicit __attribute__((used)) ThreadData( T value ) : mValue( value ), mCondition( mMutex ) {
mChanged = false;
}
//~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