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.cpp

298 lines
7.3 KiB

/*
* $Id: AmThread.cpp,v 1.12.2.2 2005/03/09 18:57:01 sayer Exp $
*
* 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
*
* For a license to use the ser 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
*/
#include "AmThread.h"
#include "log.h"
#include <unistd.h>
#include "errno.h"
#include <string>
using std::string;
AmMutex::AmMutex()
{
pthread_mutex_init(&m,NULL);
}
AmMutex::~AmMutex()
{
pthread_mutex_destroy(&m);
}
void AmMutex::lock()
{
pthread_mutex_lock(&m);
}
void AmMutex::unlock()
{
pthread_mutex_unlock(&m);
}
AmThread::AmThread()
: _stopped(true)
{
}
// int thread_nr=0;
// AmMutex thread_nr_mut;
void * AmThread::_start(void * _t)
{
AmThread* _this = (AmThread*)_t;
_this->_pid = (pid_t) _this->_td;
DBG("Thread %ld is starting.\n", (unsigned long int) _this->_pid);
_this->_stopped.set(false);
_this->run();
_this->_stopped.set(true);
//thread_nr_mut.lock();
//INFO("threads = %i\n",--thread_nr);
//thread_nr_mut.unlock();
DBG("Thread %ld is ending.\n", (unsigned long int) _this->_pid);
return NULL;
}
void AmThread::start(bool realtime)
{
// start thread realtime...seems to not improve any thing
//
// if (realtime) {
// pthread_attr_t attributes;
// pthread_attr_init(&attributes);
// struct sched_param rt_param;
// if (pthread_attr_setschedpolicy (&attributes, SCHED_FIFO)) {
// ERROR ("cannot set FIFO scheduling class for RT thread");
// }
// if (pthread_attr_setscope (&attributes, PTHREAD_SCOPE_SYSTEM)) {
// ERROR ("Cannot set scheduling scope for RT thread");
// }
// memset (&rt_param, 0, sizeof (rt_param));
// rt_param.sched_priority = 80;
// if (pthread_attr_setschedparam (&attributes, &rt_param)) {
// ERROR ("Cannot set scheduling priority for RT thread (%s)", strerror (errno));
// }
// int res;
// _pid = 0;
// res = pthread_create(&_td,&attributes,_start,this);
// if (res != 0) {
// ERROR("pthread create of RT thread failed with code %s\n", strerror(res));
// ERROR("Trying to start normal thread...\n");
// _pid = 0;
// res = pthread_create(&_td,NULL,_start,this);
// if (res != 0) {
// ERROR("pthread create failed with code %i\n", res);
// }
// }
// DBG("Thread %ld is just created.\n", (unsigned long int) _pid);
// return;
// }
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,1024*1024);// 1 MB
int res;
_pid = 0;
res = pthread_create(&_td,&attr,_start,this);
pthread_attr_destroy(&attr);
if (res != 0) {
ERROR("pthread create failed with code %i\n", res);
throw string("thread could not be started");
}
// thread_nr_mut.lock();
// INFO("threads = %i\n",++thread_nr);
// thread_nr_mut.unlock();
DBG("Thread %ld is just created.\n", (unsigned long int) _pid);
}
void AmThread::stop()
{
_m_td.lock();
// gives the thread a chance to clean up
DBG("Thread %ld (%ld) calling on_stop, give it a chance to clean up.\n",
(unsigned long int) _pid, _td);
try { on_stop(); } catch(...) {}
int res;
if ((res = pthread_detach(_td)) != 0) {
if (res == EINVAL) {
WARN("pthread_detach failed with code EINVAL: thread already in detached state.\n");
} else if (res == ESRCH) {
WARN("pthread_detach failed with code ESRCH: thread could not be found.\n");
} else {
WARN("pthread_detach failed with code %i\n", res);
}
}
DBG("Thread %ld (%ld) finished detach.\n", (unsigned long int) _pid, _td);
//pthread_cancel(_td);
_m_td.unlock();
}
void AmThread::cancel() {
_m_td.lock();
int res;
if ((res = pthread_cancel(_td)) != 0) {
ERROR("pthread_cancel failed with code %i\n", res);
} else {
DBG("Thread %ld is canceled.\n", (unsigned long int) _pid);
_stopped.set(true);
}
_m_td.unlock();
}
void AmThread::join()
{
if(!is_stopped())
pthread_join(_td,NULL);
}
int AmThread::setRealtime() {
// set process realtime
// int policy;
// struct sched_param rt_param;
// memset (&rt_param, 0, sizeof (rt_param));
// rt_param.sched_priority = 80;
// int res = sched_setscheduler(0, SCHED_FIFO, &rt_param);
// if (res) {
// ERROR("sched_setscheduler failed. Try to run SEMS as root or suid.\n");
// }
// policy = sched_getscheduler(0);
// std::string str_policy = "unknown";
// switch(policy) {
// case SCHED_OTHER: str_policy = "SCHED_OTHER"; break;
// case SCHED_RR: str_policy = "SCHED_RR"; break;
// case SCHED_FIFO: str_policy = "SCHED_FIFO"; break;
// }
// DBG("Thread has now policy '%s' - priority 80 (from %d to %d).\n", str_policy.c_str(),
// sched_get_priority_min(policy), sched_get_priority_max(policy));
// return 0;
return 0;
}
AmThreadWatcher* AmThreadWatcher::_instance=0;
AmMutex AmThreadWatcher::_inst_mut;
AmThreadWatcher::AmThreadWatcher()
: _run_cond(false)
{
}
AmThreadWatcher* AmThreadWatcher::instance()
{
_inst_mut.lock();
if(!_instance){
_instance = new AmThreadWatcher();
_instance->start();
}
_inst_mut.unlock();
return _instance;
}
void AmThreadWatcher::add(AmThread* t)
{
DBG("trying to add thread %ld to thread watcher.\n", (unsigned long int) t->_pid);
q_mut.lock();
thread_queue.push(t);
_run_cond.set(true);
q_mut.unlock();
DBG("added thread %ld to thread watcher.\n", (unsigned long int) t->_pid);
}
void AmThreadWatcher::on_stop()
{
}
void AmThreadWatcher::run()
{
for(;;){
_run_cond.wait_for();
// Let some time for to threads
// to stop by themselves
sleep(10);
q_mut.lock();
DBG("Thread watcher starting its work\n");
try {
queue<AmThread*> n_thread_queue;
while(!thread_queue.empty()){
AmThread* cur_thread = thread_queue.front();
thread_queue.pop();
q_mut.unlock();
DBG("thread %ld is to be processed in thread watcher.\n", (unsigned long int) cur_thread->_pid);
if(cur_thread->is_stopped()){
DBG("thread %ld has been destroyed.\n", (unsigned long int) cur_thread->_pid);
delete cur_thread;
}
else {
DBG("thread %ld still running.\n", (unsigned long int) cur_thread->_pid);
n_thread_queue.push(cur_thread);
}
q_mut.lock();
}
swap(thread_queue,n_thread_queue);
}catch(...){
/* this one is IMHO very important, as lock is called in try block! */
ERROR("unexpected exception, state may be invalid!\n");
}
bool more = !thread_queue.empty();
q_mut.unlock();
DBG("Thread watcher finished\n");
if(!more)
_run_cond.set(false);
}
}