blob: 199ef2d9a724cb1f137958d41a78d06a42bc832a [file] [log] [blame]
#include "third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_pool_manager.h"
#include <algorithm>
#include "base/bind.h"
#include "third_party/blink/renderer/platform/scheduler/test/fuzzer/sequence_manager_fuzzer_processor.h"
#include "third_party/blink/renderer/platform/scheduler/test/fuzzer/simple_thread_impl.h"
#include "third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_manager.h"
namespace base {
namespace sequence_manager {
ThreadPoolManager::ThreadPoolManager(SequenceManagerFuzzerProcessor* processor)
: processor_(processor),
next_time_(base::TimeTicks::Max()),
ready_to_compute_time_(&lock_),
ready_to_advance_time_(&lock_),
ready_to_terminate_(&lock_),
ready_to_execute_threads_(&lock_),
ready_for_next_round_(&lock_),
threads_waiting_to_compute_time_(0),
threads_waiting_to_advance_time_(0),
threads_ready_for_next_round_(0),
threads_ready_to_terminate_(0),
all_threads_ready_(true),
initial_threads_created_(false) {
DCHECK(processor_);
}
ThreadPoolManager::~ThreadPoolManager() = default;
void ThreadPoolManager::CreateThread(
const google::protobuf::RepeatedPtrField<
SequenceManagerTestDescription::Action>& initial_thread_actions,
base::TimeTicks time) {
SimpleThread* thread;
{
AutoLock lock(lock_);
threads_.push_back(std::make_unique<SimpleThreadImpl>(
this, time,
BindOnce(&ThreadPoolManager::StartThread, Unretained(this),
initial_thread_actions)));
thread = threads_.back().get();
}
thread->Start();
}
void ThreadPoolManager::StartThread(
const google::protobuf::RepeatedPtrField<
SequenceManagerTestDescription::Action>& initial_thread_actions,
ThreadManager* thread_manager) {
{
AutoLock lock(lock_);
thread_managers_.push_back(thread_manager);
while (!initial_threads_created_)
ready_to_execute_threads_.Wait();
}
thread_manager->ExecuteThread(initial_thread_actions);
}
void ThreadPoolManager::AdvanceClockSynchronouslyByPendingTaskDelay(
ThreadManager* thread_manager) {
ThreadReadyToComputeTime();
{
AutoLock lock(lock_);
while (threads_waiting_to_compute_time_ != threads_.size())
ready_to_compute_time_.Wait();
next_time_ =
std::min(next_time_, thread_manager->NowTicks() +
thread_manager->NextPendingTaskDelay());
threads_waiting_to_advance_time_++;
if (threads_waiting_to_advance_time_ == threads_.size()) {
threads_waiting_to_compute_time_ = 0;
ready_to_advance_time_.Broadcast();
}
}
AdvanceThreadClock(thread_manager);
}
void ThreadPoolManager::AdvanceClockSynchronouslyToTime(
ThreadManager* thread_manager,
base::TimeTicks time) {
ThreadReadyToComputeTime();
{
AutoLock lock(lock_);
while (threads_waiting_to_compute_time_ != threads_.size())
ready_to_compute_time_.Wait();
next_time_ = std::min(next_time_, time);
threads_waiting_to_advance_time_++;
if (threads_waiting_to_advance_time_ == threads_.size()) {
threads_waiting_to_compute_time_ = 0;
ready_to_advance_time_.Broadcast();
}
}
AdvanceThreadClock(thread_manager);
}
void ThreadPoolManager::ThreadReadyToComputeTime() {
AutoLock lock(lock_);
while (!all_threads_ready_)
ready_for_next_round_.Wait();
threads_waiting_to_compute_time_++;
if (threads_waiting_to_compute_time_ == threads_.size()) {
all_threads_ready_ = false;
ready_to_compute_time_.Broadcast();
}
}
void ThreadPoolManager::AdvanceThreadClock(ThreadManager* thread_manager) {
AutoLock lock(lock_);
while (threads_waiting_to_advance_time_ != threads_.size())
ready_to_advance_time_.Wait();
thread_manager->AdvanceMockTickClock(next_time_ - thread_manager->NowTicks());
threads_ready_for_next_round_++;
if (threads_ready_for_next_round_ == threads_.size()) {
threads_waiting_to_advance_time_ = 0;
threads_ready_for_next_round_ = 0;
all_threads_ready_ = true;
next_time_ = base::TimeTicks::Max();
ready_for_next_round_.Broadcast();
}
}
void ThreadPoolManager::StartInitialThreads() {
{
AutoLock lock(lock_);
initial_threads_created_ = true;
}
ready_to_execute_threads_.Broadcast();
}
void ThreadPoolManager::WaitForAllThreads() {
if (threads_.IsEmpty())
return;
AutoLock lock(lock_);
while (threads_ready_to_terminate_ != threads_.size())
ready_to_terminate_.Wait();
}
void ThreadPoolManager::ThreadDone() {
AutoLock lock(lock_);
threads_ready_to_terminate_++;
if (threads_ready_to_terminate_ == threads_.size()) {
// Only the main thread waits for this event.
ready_to_terminate_.Signal();
}
}
SequenceManagerFuzzerProcessor* ThreadPoolManager::processor() const {
return processor_;
}
ThreadManager* ThreadPoolManager::GetThreadManagerFor(uint64_t thread_id) {
AutoLock lock(lock_);
if (thread_managers_.IsEmpty())
return nullptr;
int id = thread_id % thread_managers_.size();
return thread_managers_[id];
}
Vector<ThreadManager*> ThreadPoolManager::GetAllThreadManagers() {
AutoLock lock(lock_);
return thread_managers_;
}
} // namespace sequence_manager
} // namespace base