Files
Webcam/include/platform/async/job.cpp

216 lines
5.1 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include "async/job.h"
#include "memory/memory.h"
#include "log/log.h"
using namespace GS::ASync;
using namespace GS::Threading;
#ifndef _DEBUG
#define __ENABLE_ITT_API__ 0
#endif
#if __ENABLE_ITT_API__
#include "ittnotify.h"
static __itt_domain *domain = NULL;
#endif
//------------------------------------------------------------------------------
void JobWorkerThread::Execute()
{
running.Set(1);
Thread::SetName(GS::String::Format("Job Worker Thread %d", worker_id));
while (running.Get() == 1)
{
// Execute as much jobs as possible until starvation.
while (manager.ExecutePendingJob(worker_id));
// Wait for notification on the queue event.
manager.job_queued_event.Wait();
}
running.Set(0);
}
void JobWorkerThread::Stop()
{ running.Set(2); }
bool JobWorkerThread::IsRunning() const
{ return running.Get() > 0; }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool JobManager::CreateJobThreadPool(uint count)
{
FreeJobThreadPool();
if (!pool.Allocate(count))
return false;
for (uint n = 0; n < count; ++n)
if ((pool[n] = new JobWorkerThread(*this, n + 1)) == NULL)
__ERR__(__LOG_E__ << "Failed to allocate a job worker thread.\n", false)
// Create workers.
for (uint n = 0; n < count; ++n)
if (!pool[n]->Start())
__LOG_W__ << "Failed to create worker thread " << pool[n]->GetWorkerId() << ".\n";
return true;
}
void JobManager::FreeJobThreadPool()
{
// Set thread exit flag.
for (uint n = 0; n < pool.GetCount(); ++n)
pool[n]->Stop();
// Trigger event so that the thread processes the exit flag.
for (uint n = 0; n < pool.GetCount(); ++n)
job_queued_event.Trigger();
// Join threads.
for (uint n = 0; n < pool.GetCount(); ++n)
if (!pool[n]->IsRunning())
delete pool[n];
pool.Free();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool JobManager::EnqueueJob(Job *job, JobGroup *group)
{
if (pool.GetCount() == 0)
{
job->Execute(0);
job->done.Set(1);
}
else
{
job->done.Set(0);
if (group)
{
MutexLock lock(group->job_list_mutex);
group->job_list.Add(job);
}
{
#if __USE_LOCK_FREE_JOB_QUEUE__
while (!pending_queue.enqueue(job)) {}
#else
nMutexLock lock(pending_queue_mutex);
pending_queue.Push(job);
#endif
}
}
job_queued_event.Trigger(); // wake workers
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool JobManager::JoinJob(Job *job, bool blocking)
{
if (job)
while (job->done.Get() == 0) // spinlock
if (!blocking)
return false;
return true;
}
bool JobManager::JoinGroup(JobGroup *group, bool blocking)
{
if (group)
for (bool done = false; !done; ) // spinlock
{
done = true;
{
MutexLock glock(group->job_list_mutex);
ListForeachPtr(Job *, job, group->job_list)
if (job->done.Get() == 0)
{
done = false;
break;
}
}
if (!blocking)
return done;
Thread::Switch();
}
return true;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool JobManager::ExecutePendingJob(uint worker_id)
{
// Look for a job to execute.
Job *job = NULL;
{
#if __USE_LOCK_FREE_JOB_QUEUE__
pending_queue.dequeue(job);
#else
nMutexLock pending_lock(pending_queue_mutex);
if (pending_queue.GetCount() > 0)
{
job = pending_queue.Top();
pending_queue.Pop();
}
#endif
}
// Execute job.
if (job)
{
#if __ENABLE_ITT_API__
__itt_task_begin(domain, __itt_null, __itt_null, __itt_string_handle_create(job->name));
#endif
// job->time_start = Platform::Get().GetTime();
job->Execute(worker_id);
job->done.Set(1);
// job->time_end = Platform::Get().GetTime();
Thread::Switch(); // let other workers do their job
#if __ENABLE_ITT_API__
__itt_task_end(domain);
#endif
}
return asbool(job);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
uint JobManager::GetWorkerPoolSize() const
{ return pool.GetCount(); }
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
JobManager::JobManager() : pending_queue(256)
{
#if __ENABLE_ITT_API__
domain = __itt_domain_create("GS.JobManager");
#endif
#if (__USE_LOCK_FREE_JOB_QUEUE__ == 0)
pending_queue_mutex = new nMutex;
#endif
}
JobManager::~JobManager()
{ FreeJobThreadPool(); }
JobGroup::JobGroup()
{ job_list_mutex = new Mutex; }
//------------------------------------------------------------------------------