Files
Aerofoil/PortabilityLayer/WorkerThread.cpp
2020-11-01 20:59:52 -05:00

153 lines
3.0 KiB
C++

#include "WorkerThread.h"
#include "HostSystemServices.h"
#include "HostThreadEvent.h"
#include <stdlib.h>
#include <new>
namespace PortabilityLayer
{
class WorkerThreadImpl final : public WorkerThread
{
public:
WorkerThreadImpl();
bool Init();
void Destroy() override;
void AsyncExecuteTask(Callback_t callback, void *context) override;
private:
~WorkerThreadImpl() override;
static int StaticThreadFuncThunk(void *context);
int ThreadFunc();
HostThreadEvent *m_wakeSignal;
HostThreadEvent *m_wakeConsumedSignal;
Callback_t m_waitingCallback;
void *m_waitingContext;
bool m_terminated;
bool m_threadRunning;
};
}
void PortabilityLayer::WorkerThreadImpl::Destroy()
{
this->~WorkerThreadImpl();
free(this);
}
void PortabilityLayer::WorkerThreadImpl::AsyncExecuteTask(PortabilityLayer::WorkerThread::Callback_t callback, void *context)
{
m_waitingCallback = callback;
m_waitingContext = context;
m_wakeSignal->Signal();
m_wakeConsumedSignal->Wait();
}
PortabilityLayer::WorkerThreadImpl::WorkerThreadImpl()
: m_wakeSignal(nullptr)
, m_wakeConsumedSignal(nullptr)
, m_waitingCallback(nullptr)
, m_waitingContext(nullptr)
, m_terminated(false)
, m_threadRunning(false)
{
}
PortabilityLayer::WorkerThreadImpl::~WorkerThreadImpl()
{
if (m_threadRunning)
{
m_terminated = true;
m_wakeSignal->Signal();
m_wakeConsumedSignal->Wait();
}
if (m_wakeSignal)
m_wakeSignal->Destroy();
if (m_wakeConsumedSignal)
m_wakeConsumedSignal->Destroy();
}
int PortabilityLayer::WorkerThreadImpl::StaticThreadFuncThunk(void *context)
{
return static_cast<PortabilityLayer::WorkerThreadImpl*>(context)->ThreadFunc();
}
int PortabilityLayer::WorkerThreadImpl::ThreadFunc()
{
m_wakeSignal->Wait();
m_wakeConsumedSignal->Signal();
for (;;)
{
m_wakeSignal->Wait();
if (m_terminated)
{
m_wakeConsumedSignal->Signal();
return 0;
}
else
{
Callback_t callback = m_waitingCallback;
void *context = m_waitingContext;
m_wakeConsumedSignal->Signal();
callback(context);
}
}
}
bool PortabilityLayer::WorkerThreadImpl::Init()
{
HostSystemServices *sysServices = HostSystemServices::GetInstance();
m_wakeSignal = sysServices->CreateThreadEvent(true, false);
if (!m_wakeSignal)
return false;
m_wakeConsumedSignal = sysServices->CreateThreadEvent(true, false);
if (!m_wakeConsumedSignal)
return false;
if (!sysServices->CreateThread(PortabilityLayer::WorkerThreadImpl::StaticThreadFuncThunk, this))
return false;
m_threadRunning = true;
m_wakeSignal->Signal();
m_wakeConsumedSignal->Wait();
return true;
}
PortabilityLayer::WorkerThread::WorkerThread()
{
}
PortabilityLayer::WorkerThread::~WorkerThread()
{
}
PortabilityLayer::WorkerThread *PortabilityLayer::WorkerThread::Create()
{
void *storage = malloc(sizeof(PortabilityLayer::WorkerThreadImpl));
if (!storage)
return nullptr;
PortabilityLayer::WorkerThreadImpl *thread = new (storage) PortabilityLayer::WorkerThreadImpl();
if (!thread->Init())
{
thread->Destroy();
return nullptr;
}
return thread;
}