Files
igl/external/embree/common/sys/taskscheduler_sys.cpp
T

206 lines
6.0 KiB
C++
Executable File

// ======================================================================== //
// Copyright 2009-2014 Intel Corporation //
// //
// Licensed under the Apache License, Version 2.0 (the "License"); //
// you may not use this file except in compliance with the License. //
// You may obtain a copy of the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in writing, software //
// distributed under the License is distributed on an "AS IS" BASIS, //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and //
// limitations under the License. //
// ======================================================================== //
#include "taskscheduler_sys.h"
#include "tasklogger.h"
#if 0
namespace embree
{
TaskSchedulerSys::TaskSchedulerSys()
: begin(0), end(0), tasks(16*1024) {}
void TaskSchedulerSys::add(ssize_t threadIndex, QUEUE queue, Task* task)
{
if (task->event)
task->event->inc();
mutex.lock();
/*! insert task to correct end of list */
switch (queue) {
case GLOBAL_FRONT: { size_t i = (--begin)&(tasks.size()-1); tasks[i] = task; break; }
case GLOBAL_BACK : { size_t i = (end++ )&(tasks.size()-1); tasks[i] = task; break; }
default : THROW_RUNTIME_ERROR("invalid task queue");
}
condition.broadcast();
mutex.unlock();
}
void TaskSchedulerSys::run(size_t threadIndex, size_t threadCount)
{
while (true)
{
/* wait for available task */
mutex.lock();
while ((end-begin) == 0 && !terminateThreads) {
condition.wait(mutex); continue;
}
/* terminate this thread */
if (terminateThreads) {
mutex.unlock(); return;
}
/* take next task from stack */
size_t i = (end-1)&(tasks.size()-1);
Task* task = tasks[i];
if (task == NULL || task->started <= 0) {
tasks[i] = NULL; end--; mutex.unlock(); continue;
}
task->locks++;
mutex.unlock();
TaskScheduler::Event* event = task->event;
thread2event[threadIndex].event = event;
/* run the task */
while (true) {
ssize_t elt = --task->started;
if (elt < 0) break;
if (task->run) task->run(task->runData,threadIndex,threadCount,elt,task->elts,task->event);
}
/* complete the task */
mutex.lock();
if (--task->locks == 0) {
tasks[i] = NULL;
mutex.unlock();
if (task->complete) task->complete(task->completeData,threadIndex,threadCount,task->event);
if (event) event->dec();
}
else
mutex.unlock();
}
}
void TaskSchedulerSys::terminate()
{
mutex.lock();
terminateThreads = true;
condition.broadcast();
mutex.unlock();
}
}
#else
namespace embree
{
TaskSchedulerSys::TaskSchedulerSys()
: begin(0), end(0), tasks(16*1024) {}
void TaskSchedulerSys::add(ssize_t threadIndex, QUEUE queue, Task* task)
{
if (task->event)
task->event->inc();
mutex.lock();
/*! resize array if too small */
if (end-begin == tasks.size())
{
size_t s0 = 1*tasks.size();
size_t s1 = 2*tasks.size();
tasks.resize(s1);
for (size_t i=begin; i!=end; i++)
tasks[i&(s1-1)] = tasks[i&(s0-1)];
}
/*! insert task to correct end of list */
switch (queue) {
case GLOBAL_FRONT: { size_t i = (--begin)&(tasks.size()-1); tasks[i] = task; break; }
case GLOBAL_BACK : { size_t i = (end++ )&(tasks.size()-1); tasks[i] = task; break; }
default : THROW_RUNTIME_ERROR("invalid task queue");
}
condition.broadcast();
mutex.unlock();
}
void TaskSchedulerSys::wait(size_t threadIndex, size_t threadCount, Event* event)
{
event->dec();
if (!isEnabled(threadIndex)) {
while (!event->triggered()); // FIXME: wait using events
}
else {
while (!event->triggered()) { // FIXME: wait using events
work(threadIndex,threadCount,false);
}
}
}
void TaskSchedulerSys::work(size_t threadIndex, size_t threadCount, bool wait)
{
/* wait for available task */
mutex.lock();
while (((end-begin) == 0 && !terminateThreads) || !isEnabled(threadIndex)) {
if (wait) condition.wait(mutex);
else { mutex.unlock(); return; }
}
/* terminate this thread */
if (terminateThreads) {
mutex.unlock();
return;
}
/* take next task from stack */
size_t i = (end-1)&(tasks.size()-1);
Task* task = tasks[i];
size_t elt = --task->started;
if (elt == 0) end--;
mutex.unlock();
/* run the task */
TaskScheduler::Event* event = task->event;
if (task->run) {
size_t taskID = TaskLogger::beginTask(threadIndex,task->name,elt);
task->run(task->runData,threadIndex,numEnabledThreads,elt,task->elts,task->event);
TaskLogger::endTask(threadIndex,taskID);
}
/* complete the task */
if (--task->completed == 0) {
if (task->complete) {
size_t taskID = TaskLogger::beginTask(threadIndex,task->name,0);
task->complete(task->completeData,threadIndex,numEnabledThreads,task->event);
TaskLogger::endTask(threadIndex,taskID);
}
if (event) event->dec();
}
}
void TaskSchedulerSys::run(size_t threadIndex, size_t threadCount)
{
while (!terminateThreads)
work(threadIndex,threadCount,true);
}
void TaskSchedulerSys::terminate()
{
mutex.lock();
terminateThreads = true;
condition.broadcast();
mutex.unlock();
}
}
#endif