audio-blockEngine/audio/blockEngine/Thread.cpp

240 lines
6.6 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <audio/blockEngine/debug.hpp>
#include <audio/blockEngine/Thread.hpp>
#include <unistd.h>
static const char* threadGetCharState(enum audio::blockEngine::status state) {
const char* ret = (const char*)"";
switch (state) {
case audio::blockEngine::statusNotStarted:
ret = (const char*)"NOT_STARTED";
break;
case audio::blockEngine::statusCreating:
ret = (const char*)"CREATING";
break;
case audio::blockEngine::statusStart:
ret = (const char*)"START";
break;
case audio::blockEngine::statusRun:
ret = (const char*)"RUN";
break;
case audio::blockEngine::statusStop:
ret = (const char*)"STOP";
break;
case audio::blockEngine::statusDie:
ret = (const char*)"DIE";
break;
default:
ret = (const char*)"???";
break;
}
return ret;
}
/**
* @brief change the current state of the thread.
* @param[in] _newState The new state for the thread.
*/
void audio::blockEngine::Thread::threadChangeState(enum audio::blockEngine::status _newState) {
int ret;
ethread::UniqueLock lock(m_interfaceMutex);
// debug display :
ABE_DEBUG("[" << m_id << "] '" << m_name << "' Change state : " << threadGetCharState(m_state) << " ==> " << threadGetCharState(_newState));
// set the New state
m_state = _newState;
return;
}
audio::blockEngine::Thread::Thread(const etk::String& _chainName) {
if (_chainName != "") {
m_name = _chainName;
} else {
m_name = "No-name";
ABE_WARNING("the thread has no name");
}
static int32_t threadIDBasic = 100;
m_id = threadIDBasic++;
ABE_INFO("THREAD : Allocate [" << m_id << "] name='" << m_name << "'");
m_state = audio::blockEngine::statusNotStarted;
}
audio::blockEngine::Thread::~Thread() {
ABE_INFO("THREAD : Destroy [" << m_id << "] name='" << m_name << "'");
stop();
m_thread->join();
m_thread.reset();
}
int32_t audio::blockEngine::Thread::start() {
int ret;
if (audio::blockEngine::statusDie == m_state) {
ABE_INFO("Thread [" << m_id << "] name='" << m_name << "' ==> state die ... ==> delete it ...");
stopAtEnd();
}
if (audio::blockEngine::statusNotStarted != m_state) {
ABE_ERROR("Failed to create [" << m_id << "] name='" << m_name << "' ==> the thread is not stopped ...");
return audio::blockEngine::ERR_FAIL;
}
m_state = audio::blockEngine::statusCreating;
m_thread = ememory::makeShared<ethread::Thread>([&]() { threadCall();});
// no else ==> the thread is started corectly... (we think)
return audio::blockEngine::ERR_NONE;
}
int32_t audio::blockEngine::Thread::stop() {
ABE_INFO(" Stop [" << m_id << "] name='" << m_name << "'");
// Set the stop flag for the thread :
ethread::UniqueLock lock(m_interfaceMutex);
m_flags |= 1;
return audio::blockEngine::ERR_NONE;
}
int32_t audio::blockEngine::Thread::stopAtEnd() {
int systemRet;
int32_t ret = audio::blockEngine::ERR_NONE;
ABE_INFO(" Delete [" << m_id << "] name='" << m_name << "' (StopAtEnd)");
// Request the thread stop:
ret = stop();
if (audio::blockEngine::ERR_NONE != ret) {
ABE_ERROR("The thread have a problem to stop");
return ret;
}
if (audio::blockEngine::statusNotStarted != m_state) {
m_thread.reset();
}
ethread::UniqueLock lock(m_interfaceMutex);
m_flags = 0;
m_state = audio::blockEngine::statusNotStarted;
return ret;
}
// function that might be writen for every thread
bool audio::blockEngine::Thread::stateStart() {
ABE_DEBUG("Not overwrited in the herited classes: StateStart");
// virtual function ...
return false;
}
bool audio::blockEngine::Thread::stateRun() {
ABE_DEBUG("Not overwrited in the herited classes: StateRun");
// virtual function ...
usleep(100000);
// Force the stop if this function is not overwritte
return false;
}
bool audio::blockEngine::Thread::stateStop() {
ABE_DEBUG("Not overwrited in the herited classes: StateStop");
// virtual function ...
return false;
}
void audio::blockEngine::Thread::threadCall() {
bool autoKill = false;
// Endless loop.
while(audio::blockEngine::statusDie != m_state) {
int32_t flags = 0;
{
ethread::UniqueLock lock(m_interfaceMutex);
flags = m_flags;
m_flags = 0;
}
if (flags == 1 ) {
ABE_DEBUG("Detect stop request by user...");
// action depend on the current state :
switch (m_state) {
case audio::blockEngine::statusCreating:
threadChangeState(audio::blockEngine::statusDie);
break;
case audio::blockEngine::statusStart:
threadChangeState(audio::blockEngine::statusStop);
break;
case audio::blockEngine::statusRun:
threadChangeState(audio::blockEngine::statusStop);
break;
case audio::blockEngine::statusStop:
// nothing to do ...
break;
case audio::blockEngine::statusDie:
// impossible state
break;
default:
// Should not happen
ABE_CRITICAL("Base: [" << m_id << "] '" << m_name << "' state failure ...");
break;
}
}
// Retrieve current action.
switch (m_state) {
case audio::blockEngine::statusCreating:
ABE_DEBUG("audio::blockEngine::statusCreating");
// change state :
threadChangeState(audio::blockEngine::statusStart);
break;
case audio::blockEngine::statusStart:
ABE_DEBUG("audio::blockEngine::statusStart");
// call function
autoKill = stateStart();
// a problem occured to the function
if (true == autoKill) {
// error in start ==> direct end
threadChangeState(audio::blockEngine::statusDie);
} else {
// change state :
threadChangeState(audio::blockEngine::statusRun);
}
break;
case audio::blockEngine::statusRun:
ABE_DEBUG("audio::blockEngine::statusRun");
// call function
autoKill = stateRun();
if (true == autoKill) {
ABE_DEBUG("Request AutoKill");
// error in start ==> direct end
threadChangeState(audio::blockEngine::statusStop);
}
// no else
break;
case audio::blockEngine::statusStop:
ABE_DEBUG("audio::blockEngine::statusStop");
// call function
autoKill = stateStop();
// a problem occured to the function
if (true == autoKill) {
// error in stop ==> direct end
threadChangeState(audio::blockEngine::statusDie);
} else {
// change state :
threadChangeState(audio::blockEngine::statusDie);
}
break;
case audio::blockEngine::statusDie:
ABE_DEBUG("audio::blockEngine::statusDie");
break;
default:
// Should not happen
ABE_CRITICAL("Base: state failure: [" << m_id << "] name='" << m_name << "'");
return;
}
}
// exit the thread...
ABE_INFO("Base: THEAD (END): [" << m_id << "] name='" << m_name << "'");
return;
}