zoneminder/src/zm_thread.h

270 lines
5.5 KiB
C
Raw Normal View History

//
// 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
class RecursiveMutex;
#include "zm_config.h"
#include <unistd.h>
#include <pthread.h>
2013-09-25 12:11:59 +08:00
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
#endif // HAVE_SYS_SYSCALL_H
#include "zm_exception.h"
#include "zm_utils.h"
2015-02-24 22:22:08 +08:00
#ifdef __FreeBSD__
#include <sys/thr.h>
#endif
2017-11-19 05:00:10 +08:00
class ThreadException : public Exception {
2015-02-24 22:22:08 +08:00
private:
#ifndef SOLARIS
pid_t pid() {
pid_t tid;
2015-02-24 22:22:08 +08:00
#ifdef __FreeBSD__
long lwpid;
thr_self(&lwpid);
tid = lwpid;
2015-02-24 22:22:08 +08:00
#else
#ifdef __FreeBSD_kernel__
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
# else
tid=syscall(SYS_gettid);
#endif
2015-02-24 22:22:08 +08:00
#endif
return tid;
}
#else
pthread_t pid() { return( pthread_self() ); }
#endif
public:
2020-05-08 01:44:32 +08:00
explicit ThreadException(const std::string &message) :
Exception(stringtf("(%d) ", (long int)pid())+message)
{
}
};
2017-11-19 05:00:10 +08:00
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();
};
2017-11-19 05:00:10 +08:00
class ScopedMutex {
private:
Mutex &mMutex;
public:
2017-11-19 05:00:10 +08:00
explicit ScopedMutex( Mutex &mutex ) : mMutex( mutex ) {
mMutex.lock();
}
2017-11-19 05:00:10 +08:00
~ScopedMutex() {
mMutex.unlock();
}
private:
ScopedMutex( const ScopedMutex & );
};
2018-04-12 23:29:35 +08:00
class Condition {
private:
Mutex &mMutex;
pthread_cond_t mCondition;
public:
2018-04-12 23:29:35 +08:00
explicit Condition(Mutex &mutex);
~Condition();
void wait();
2018-04-12 23:29:35 +08:00
bool wait(int secs);
bool wait(double secs);
void signal();
void broadcast();
};
2018-04-12 23:29:35 +08:00
class Semaphore : public Condition {
private:
Mutex mMutex;
public:
2018-04-12 23:29:35 +08:00
Semaphore() : Condition(mMutex) {
}
2018-04-12 23:29:35 +08:00
void wait() {
mMutex.lock();
Condition::wait();
mMutex.unlock();
}
2018-04-12 23:29:35 +08:00
bool wait(int secs) {
mMutex.lock();
2018-04-12 23:29:35 +08:00
bool result = Condition::wait(secs);
mMutex.unlock();
2018-04-12 23:29:35 +08:00
return result;
}
2018-04-12 23:29:35 +08:00
bool wait(double secs) {
mMutex.lock();
2018-04-12 23:29:35 +08:00
bool result = Condition::wait(secs);
mMutex.unlock();
2018-04-12 23:29:35 +08:00
return result;
}
2018-04-12 23:29:35 +08:00
void signal() {
mMutex.lock();
Condition::signal();
mMutex.unlock();
}
2018-04-12 23:29:35 +08:00
void broadcast() {
mMutex.lock();
Condition::broadcast();
mMutex.unlock();
}
};
2017-11-19 05:00:10 +08:00
template <class T> class ThreadData {
private:
T mValue;
mutable bool mChanged;
mutable Mutex mMutex;
mutable Condition mCondition;
public:
2020-05-08 01:44:32 +08:00
__attribute__((used)) ThreadData() :
mValue(0), mCondition(mMutex)
{
2017-11-19 05:00:10 +08:00
mChanged = false;
}
2020-05-08 01:44:32 +08:00
explicit __attribute__((used)) ThreadData(T value) :
mValue(value), mCondition(mMutex) {
2017-11-19 05:00:10 +08:00
mChanged = false;
}
2020-05-08 01:44:32 +08:00
__attribute__((used)) operator T() const {
return getValue();
}
2020-05-08 01:44:32 +08:00
__attribute__((used)) const T operator=( const T value ) {
return setValue(value);
}
2020-05-08 01:44:32 +08:00
__attribute__((used)) const T getValueImmediate() const {
return mValue;
}
2020-05-08 01:44:32 +08:00
__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;
2020-05-08 01:44:32 +08:00
__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);
};
2018-04-12 23:29:35 +08:00
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;
2016-12-29 17:31:05 +08:00
int status; // Used in various functions to get around return a local variable
protected:
Thread();
virtual ~Thread();
#ifndef SOLARIS
2018-04-12 23:29:35 +08:00
pid_t id() const {
pid_t tid;
2015-02-24 22:22:08 +08:00
#ifdef __FreeBSD__
long lwpid;
thr_self(&lwpid);
tid = lwpid;
2015-02-24 22:22:08 +08:00
#else
#ifdef __FreeBSD_kernel__
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
#else
tid=syscall(SYS_gettid);
#endif
2015-02-24 22:22:08 +08:00
#endif
2018-04-12 23:29:35 +08:00
return tid;
}
#else
2018-04-12 23:29:35 +08:00
pthread_t id() const {
return pthread_self();
}
#endif
2018-04-12 23:29:35 +08:00
void exit( int p_status = 0 ) {
//INFO( "Exiting" );
2016-04-28 21:20:56 +08:00
pthread_exit( (void *)&p_status );
}
static void *mThreadFunc( void *arg );
public:
virtual int run() = 0;
void start();
void join();
void kill( int signal );
2018-04-12 23:29:35 +08:00
bool isThread() {
return( mPid > -1 && pthread_equal( pthread_self(), mThread ) );
}
2018-04-12 23:29:35 +08:00
bool isStarted() const { return mStarted; }
bool isRunning() const { return mRunning; }
};
#endif // ZM_THREAD_H