diff options
Diffstat (limited to 'runtime/gc/task_processor.cc')
| -rw-r--r-- | runtime/gc/task_processor.cc | 125 | 
1 files changed, 125 insertions, 0 deletions
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc new file mode 100644 index 0000000000..1a3c6f5399 --- /dev/null +++ b/runtime/gc/task_processor.cc @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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 "task_processor.h" + +#include "scoped_thread_state_change.h" + +namespace art { +namespace gc { + +TaskProcessor::TaskProcessor() +    : lock_(new Mutex("Task processor lock", kReferenceProcessorLock)), is_running_(false) { +  // Piggyback off the reference processor lock level. +  cond_.reset(new ConditionVariable("Task processor condition", *lock_)); +} + +TaskProcessor::~TaskProcessor() { +  delete lock_; +} + +void TaskProcessor::AddTask(Thread* self, HeapTask* task) { +  ScopedThreadStateChange tsc(self, kBlocked); +  MutexLock mu(self, *lock_); +  tasks_.insert(task); +  cond_->Signal(self); +} + +HeapTask* TaskProcessor::GetTask(Thread* self) { +  ScopedThreadStateChange tsc(self, kBlocked); +  MutexLock mu(self, *lock_); +  while (true) { +    if (tasks_.empty()) { +      if (!is_running_) { +        return nullptr; +      } +      cond_->Wait(self);  // Empty queue, wait until we are signalled. +    } else { +      // Non empty queue, look at the top element and see if we are ready to run it. +      const uint64_t current_time = NanoTime(); +      HeapTask* task = *tasks_.begin(); +      // If we are shutting down, return the task right away without waiting. Otherwise return the +      // task if it is late enough. +      uint64_t target_time = task->GetTargetRunTime(); +      if (!is_running_ || target_time <= current_time) { +        tasks_.erase(tasks_.begin()); +        return task; +      } +      DCHECK_GT(target_time, current_time); +      // Wait untl we hit the target run time. +      const uint64_t delta_time = target_time - current_time; +      const uint64_t ms_delta = NsToMs(delta_time); +      const uint64_t ns_delta = delta_time - MsToNs(ms_delta); +      cond_->TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta)); +    } +  } +  UNREACHABLE(); +  return nullptr; +} + +void TaskProcessor::UpdateTargetRunTime(Thread* self, HeapTask* task, uint64_t new_target_time) { +  MutexLock mu(self, *lock_); +  // Find the task. +  auto range = tasks_.equal_range(task); +  for (auto it = range.first; it != range.second; ++it) { +    if (*it == task) { +      // Check if the target time was updated, if so re-insert then wait. +      if (new_target_time != task->GetTargetRunTime()) { +        tasks_.erase(it); +        task->SetTargetRunTime(new_target_time); +        tasks_.insert(task); +        // If we became the first task then we may need to signal since we changed the task that we +        // are sleeping on. +        if (*tasks_.begin() == task) { +          cond_->Signal(self); +        } +        return; +      } +    } +  } +} + +bool TaskProcessor::IsRunning() const { +  MutexLock mu(Thread::Current(), *lock_); +  return is_running_; +} + +void TaskProcessor::Stop(Thread* self) { +  MutexLock mu(self, *lock_); +  is_running_ = false; +  cond_->Broadcast(self); +} + +void TaskProcessor::Start(Thread* self) { +  MutexLock mu(self, *lock_); +  is_running_ = true; +} + +void TaskProcessor::RunAllTasks(Thread* self) { +  while (true) { +    // Wait and get a task, may be interrupted. +    HeapTask* task = GetTask(self); +    if (task != nullptr) { +      task->Run(self); +      task->Finalize(); +    } else if (!IsRunning()) { +      break; +    } +  } +} + +}  // namespace gc +}  // namespace art  |