/*
* Copyright (C) 2015 by Multi-Tech Systems
*
* This file is part of libmts.
*
* libmts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* libmts 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libmts. If not, see .
*
*/
#include
#include
#include
#include
using namespace MTS;
Thread::Thread(const std::string& name, bool managed)
: m_pThread(NULL)
, m_sName(name)
, m_bManaged(managed)
, m_bComplete(true)
, m_bCanceled(true)
{
printConfig("Thread| %s()", getName().c_str());
m_apThreadLock.reset(new Lock());
m_apStateLock.reset(new Lock());
m_apCompleteCondition.reset(m_apStateLock->createCondition());
}
Thread::~Thread() {
m_bCanceled = true;
Thread::stop();
m_apCompleteCondition.reset();
m_apStateLock.reset();
m_apThreadLock.reset();
printConfig("Thread| %s - deconstructed", getName().c_str());
}
void Thread::sleep(uint32_t millis) {
#ifdef WIN32
Sleep(millis);
#else
Lock lock;
Condition* condition = lock.createCondition();
lock.lock();
condition->wait(millis);
lock.unlock();
delete condition;
#endif
}
const std::string& Thread::getName() const {
return m_sName;
}
void Thread::start() {
m_apThreadLock->lock();
try {
if (m_pThread == NULL) {
reset();
#ifdef WIN32
m_pThread = CreateThread(NULL, 0, &doInBackground, this, 0, NULL);
#else
m_pThread = new (std::nothrow) pthread_t;
if (m_pThread != NULL) {
const int result = pthread_create(m_pThread, NULL,
&doInBackground, this);
assert(result == 0);
if (result != 0) {
delete m_pThread;
m_pThread = NULL;
}
}
#endif
assert(m_pThread != NULL);
if (m_pThread != NULL) {
printConfig("Thread| %s - started (%p)",
getName().c_str(), m_pThread);
} else {
printWarning("Thread| Failed to start runnable %s",
getName().c_str());
m_apStateLock->lock();
m_bCanceled = true;
m_bComplete = true;
m_apStateLock->unlock();
}
}
} catch (...) {
printWarning("Thread| Failed to start runnable %s", getName().c_str());
assert(false);
}
m_apThreadLock->unlock();
}
void Thread::stop() {
m_apThreadLock->lock();
cancel();
if (m_pThread != NULL) {
wait(1500);
#ifdef WIN32
if (!isDone()) {
TerminateThread(m_pThread, 1);
printConfig("Thread| %s - terminated", getName().c_str());
}
const BOOL ok = CloseHandle(m_pThread);
assert(ok);
#else
if (!isDone()) {
printConfig("Thread| %s - terminated", getName().c_str());
}
delete m_pThread;
#endif
m_pThread = NULL;
} else if (!isDone()) {
done();
}
m_apThreadLock->unlock();
}
void Thread::wait() {
m_apStateLock->lock();
if (!m_bComplete) {
m_apCompleteCondition->wait();
}
m_apStateLock->unlock();
}
void Thread::wait(uint32_t millis) {
m_apStateLock->lock();
if (!m_bComplete) {
m_apCompleteCondition->wait(millis);
}
m_apStateLock->unlock();
}
bool Thread::isAlive() const {
bool result = false;
m_apThreadLock->lock();
result = (m_pThread != NULL);
m_apThreadLock->unlock();
return result;
}
bool Thread::isCanceled() const {
bool result = false;
m_apStateLock->lock();
result = m_bCanceled;
m_apStateLock->unlock();
return result;
}
void Thread::cancel() {
m_apStateLock->lock();
if (!m_bCanceled) {
m_bCanceled = true;
printConfig("Thread| %s - cancelled", getName().c_str());
}
m_apStateLock->unlock();
}
bool Thread::isDone() const {
bool result = false;
m_apStateLock->lock();
result = m_bComplete;
m_apStateLock->unlock();
return result;
}
void Thread::done() {
m_apStateLock->lock();
m_bComplete = true;
m_apCompleteCondition->signal();
printConfig("Thread| %s - done", getName().c_str());
m_apStateLock->unlock();
}
void Thread::reset() {
m_apStateLock->lock();
m_bCanceled = false;
m_bComplete = false;
m_apStateLock->unlock();
}
bool Thread::isManaged() const {
return m_bManaged;
}
#ifdef WIN32
DWORD WINAPI Thread::doInBackground(__in LPVOID parameter) {
#else
void* Thread::doInBackground(void* parameter) {
#endif
Thread* runnable = static_cast(parameter);
assert(runnable != NULL);
if (runnable != NULL) {
printConfig("Thread| %s - initializing\n", runnable->getName().c_str());
try {
runnable->run();
} catch (...) {
printWarning("Thread| exception caught while running %s",
runnable->getName().c_str());
}
printConfig("Thread| %s - finalizing", runnable->getName().c_str());
bool managed = runnable->isManaged();
runnable->done();
if (!managed) {
printConfig("Thread| %s - deleted", runnable->getName().c_str());
delete runnable;
}
}
return 0;
}