mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
5.6 KiB
286 lines
5.6 KiB
/*
|
|
* Copyright (C) 2002-2003 Fhg Fokus
|
|
*
|
|
* This file is part of SEMS, a free SIP media server.
|
|
*
|
|
* SEMS 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 released under
|
|
* the GPL with the additional exemption that compiling, linking,
|
|
* and/or using OpenSSL is allowed.
|
|
*
|
|
* For a license to use the SEMS software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* SEMS 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
/** @file AmThread.h */
|
|
#ifndef _AmThread_h_
|
|
#define _AmThread_h_
|
|
|
|
#include <pthread.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
|
|
#include <queue>
|
|
|
|
/**
|
|
* \brief C++ Wrapper class for pthread mutex
|
|
*/
|
|
class AmMutex
|
|
{
|
|
pthread_mutex_t m;
|
|
|
|
public:
|
|
AmMutex(bool recursive = false);
|
|
~AmMutex();
|
|
void lock();
|
|
void unlock();
|
|
};
|
|
|
|
/**
|
|
* \brief Simple lock class
|
|
*/
|
|
class AmLock
|
|
{
|
|
AmMutex& m;
|
|
public:
|
|
AmLock(AmMutex& _m) : m(_m) {
|
|
m.lock();
|
|
}
|
|
~AmLock(){
|
|
m.unlock();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief Shared variable.
|
|
*
|
|
* Include a variable and its mutex.
|
|
* @warning Don't use safe functions (set,get)
|
|
* within a {lock(); ... unlock();} block. Use
|
|
* unsafe function instead.
|
|
*/
|
|
template<class T>
|
|
class AmSharedVar
|
|
{
|
|
T t;
|
|
AmMutex m;
|
|
|
|
public:
|
|
AmSharedVar(const T& _t) : t(_t) {}
|
|
AmSharedVar() {}
|
|
|
|
T get() {
|
|
lock();
|
|
T res = unsafe_get();
|
|
unlock();
|
|
return res;
|
|
}
|
|
|
|
void set(const T& new_val) {
|
|
lock();
|
|
unsafe_set(new_val);
|
|
unlock();
|
|
}
|
|
|
|
void lock() { m.lock(); }
|
|
void unlock() { m.unlock(); }
|
|
|
|
const T& unsafe_get() { return t; }
|
|
void unsafe_set(const T& new_val) { t = new_val; }
|
|
};
|
|
|
|
/**
|
|
* \brief C++ Wrapper class for pthread condition
|
|
*/
|
|
template<class T>
|
|
class AmCondition
|
|
{
|
|
T t;
|
|
pthread_mutex_t m;
|
|
pthread_cond_t cond;
|
|
|
|
void init_cond() {
|
|
pthread_mutex_init(&m,NULL);
|
|
pthread_cond_init(&cond,NULL);
|
|
}
|
|
|
|
public:
|
|
AmCondition() : t() { init_cond(); }
|
|
AmCondition(const T& _t) : t(_t) { init_cond(); }
|
|
|
|
~AmCondition()
|
|
{
|
|
pthread_cond_destroy(&cond);
|
|
pthread_mutex_destroy(&m);
|
|
}
|
|
|
|
/** Change the condition's value. */
|
|
void set(const T& newval)
|
|
{
|
|
pthread_mutex_lock(&m);
|
|
t = newval;
|
|
if(t)
|
|
pthread_cond_broadcast(&cond);
|
|
pthread_mutex_unlock(&m);
|
|
}
|
|
|
|
T get()
|
|
{
|
|
T val;
|
|
pthread_mutex_lock(&m);
|
|
val = t;
|
|
pthread_mutex_unlock(&m);
|
|
return val;
|
|
}
|
|
|
|
/** Waits for the condition to be true. */
|
|
void wait_for()
|
|
{
|
|
pthread_mutex_lock(&m);
|
|
while(!t){
|
|
pthread_cond_wait(&cond,&m);
|
|
}
|
|
pthread_mutex_unlock(&m);
|
|
}
|
|
|
|
/** Waits for the condition to be true or a timeout. */
|
|
bool wait_for_to(unsigned long msec)
|
|
{
|
|
struct timeval now;
|
|
struct timespec timeout;
|
|
int retcode = 0;
|
|
bool ret = false;
|
|
|
|
gettimeofday(&now, NULL);
|
|
timeout.tv_sec = now.tv_sec + (msec / 1000);
|
|
timeout.tv_nsec = (now.tv_usec + (msec % 1000)*1000)*1000;
|
|
if(timeout.tv_nsec >= 1000000000){
|
|
timeout.tv_sec++;
|
|
timeout.tv_nsec -= 1000000000;
|
|
}
|
|
|
|
pthread_mutex_lock(&m);
|
|
while(!t && !retcode){
|
|
retcode = pthread_cond_timedwait(&cond,&m, &timeout);
|
|
}
|
|
|
|
if(t) ret = true;
|
|
pthread_mutex_unlock(&m);
|
|
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief C++ Wrapper class for pthread
|
|
*/
|
|
class AmThread
|
|
{
|
|
pthread_t _td;
|
|
AmMutex _m_td;
|
|
|
|
AmSharedVar<bool> _stopped;
|
|
|
|
static void* _start(void*);
|
|
|
|
protected:
|
|
virtual void run()=0;
|
|
virtual void on_stop()=0;
|
|
|
|
public:
|
|
unsigned long _pid;
|
|
AmThread();
|
|
virtual ~AmThread() {}
|
|
|
|
virtual void onIdle() {}
|
|
|
|
/** Start it ! */
|
|
void start();
|
|
/** Stop it ! */
|
|
void stop();
|
|
/** @return true if this thread doesn't run. */
|
|
bool is_stopped() { return _stopped.get(); }
|
|
/** Wait for this thread to finish */
|
|
void join();
|
|
/** kill the thread (if pthread_setcancelstate(PTHREAD_CANCEL_ENABLED) has been set) **/
|
|
void cancel();
|
|
|
|
int setRealtime();
|
|
};
|
|
|
|
/**
|
|
* \brief Container/garbage collector for threads.
|
|
*
|
|
* AmThreadWatcher waits for threads to stop
|
|
* and delete them.
|
|
* It gets started automatically when needed.
|
|
* Once you added a thread to the container,
|
|
* there is no mean to get it out.
|
|
*/
|
|
class AmThreadWatcher: public AmThread
|
|
{
|
|
static AmThreadWatcher* _instance;
|
|
static AmMutex _inst_mut;
|
|
|
|
std::queue<AmThread*> thread_queue;
|
|
AmMutex q_mut;
|
|
|
|
/** the daemon only runs if this is true */
|
|
AmCondition<bool> _run_cond;
|
|
|
|
AmThreadWatcher();
|
|
void run();
|
|
void on_stop();
|
|
|
|
public:
|
|
static AmThreadWatcher* instance();
|
|
void add(AmThread*);
|
|
};
|
|
|
|
template<class T>
|
|
class AmThreadLocalStorage
|
|
{
|
|
pthread_key_t key;
|
|
|
|
static void __del_tls_obj(void* obj) {
|
|
delete static_cast<T*>(obj);
|
|
}
|
|
|
|
public:
|
|
AmThreadLocalStorage() {
|
|
pthread_key_create(&key,__del_tls_obj);
|
|
}
|
|
|
|
~AmThreadLocalStorage() {
|
|
pthread_key_delete(key);
|
|
}
|
|
|
|
T* get() {
|
|
return static_cast<T*>(pthread_getspecific(key));
|
|
}
|
|
|
|
void set(T* p) {
|
|
pthread_setspecific(key,(void*)p);
|
|
}
|
|
};
|
|
|
|
#endif
|
|
|
|
// Local Variables:
|
|
// mode:C++
|
|
// End:
|
|
|