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.
sems/core/AmThread.h

224 lines
5.0 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 <sys/time.h>
#include <time.h>
#include <errno.h>
#include <list>
#include <mutex>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <optional>
using std::lock_guard;
using std::atomic_bool;
class SdNotifier;
/**
* \brief Wrapper class for std::mutex
*/
class AmMutex : public std::mutex
{
public:
AmMutex() : std::mutex() {}
AmMutex(const AmMutex &) : std::mutex() {}
void operator=(const AmMutex &) {}
};
/**
* \brief Wrapper class for std::condition_variable
*/
class AmCondition
{
bool t = false;
std::mutex m;
std::condition_variable cond;
public:
AmCondition() = default;
AmCondition(const bool& _t) : t(_t) {}
/** Change the condition's value. */
void set(const bool newval)
{
std::lock_guard<std::mutex> l(m);
t = newval;
if(t)
cond.notify_all();
}
bool get()
{
std::lock_guard<std::mutex> l(m);
return t;
}
/** Waits for the condition to be true. */
void wait_for()
{
std::unique_lock<std::mutex> l(m);
while(!t){
cond.wait(l);
}
}
/** Waits for the condition to be true or a timeout. */
bool wait_for_to(unsigned long msec)
{
auto timeout = std::chrono::system_clock::now();
timeout += std::chrono::milliseconds(msec);
std::unique_lock<std::mutex> l(m);
while(!t){
auto retcode = cond.wait_until(l, timeout);
if (retcode == std::cv_status::timeout)
break;
}
return t;
}
};
/**
* \brief Wrapper class for std::thread
*/
class AmThread
{
std::thread _td;
enum state {
idle, // not started yet
running,
stopping, // waiting to stop
stopped, // after stop
};
enum join_state {
unjoined, // nobody joining/joined yet
joining, // one thread is joining
joined, // has been joined
};
state _state;
join_state _joined;
void _start();
/** Initialise to true in subclasses that call the ready() method */
bool _triggers_ready;
protected:
// protects `_state`, `_joined`, and anything else the subclass wants to use it for,
// primarily meant to determine whether a thread should run or not
std::mutex run_mut;
// can be used as a waker for threads running in a loop
std::condition_variable run_cond;
virtual void run()=0;
virtual void on_stop() {};
/** @return true if this thread ought to stop, without obtaining run_mut. */
bool stop_requested_unlocked() const { return _state == stopping; }
/** @return true if this thread ought to stop. */
bool stop_requested() {
std::lock_guard<std::mutex> _l(run_mut);
return stop_requested_unlocked();
}
std::optional<std::reference_wrapper<SdNotifier>> _sd_notifier;
/** Signal that the thread is ready to do its job */
void ready();
public:
unsigned long _pid;
AmThread(bool triggers_ready = false)
: _state(state::idle),
_joined(join_state::unjoined),
_triggers_ready(triggers_ready),
_pid(0)
{}
virtual ~AmThread();
/** Start it ! */
void start();
void start(SdNotifier&);
/** Stop it ! */
void stop();
/** Wait for this thread to finish */
void join();
/** @return true if this thread has finished. */
bool is_stopped() {
std::lock_guard<std::mutex> _l(run_mut);
return _state == stopped;
}
};
/**
* \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::list<AmThread*> thread_list;
AmThreadWatcher() {}
void run();
public:
static AmThreadWatcher* instance();
void add(AmThread*);
};
#endif
// Local Variables:
// mode:C++
// End: