blob: 0336ad697a4d16988e89ddf1cf99d7c5c9444432 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "peridot/lib/util/idle_waiter.h"
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
namespace util {
IdleWaiter::Activity::Activity(fxl::WeakPtr<IdleWaiter> tracker)
: tracker_(tracker) {
tracker_->activity_ = this;
}
IdleWaiter::Activity::~Activity() {
if (tracker_) {
tracker_->activity_ = nullptr;
if (tracker_->loop_) {
tracker_->PostIdleCheck();
}
}
}
IdleWaiter::IdleWaiter() : weak_ptr_factory_(this) {}
IdleWaiter::~IdleWaiter() = default;
void IdleWaiter::SetLoop(async::Loop* loop) {
FXL_DCHECK(!loop_);
loop_ = loop;
}
IdleWaiter::ActivityToken IdleWaiter::RegisterOngoingActivity() {
// !loop_ for unit tests
FXL_DCHECK(!loop_ || loop_->dispatcher() == async_get_default_dispatcher());
if (activity_) {
return ActivityToken(activity_);
} else {
// |activity_| is set in the |Activity| constructor and cleared in
// the destructor
return fxl::MakeRefCounted<Activity>(weak_ptr_factory_.GetWeakPtr());
}
}
void IdleWaiter::WaitUntilIdle(fit::closure callback) {
callbacks_.push_back(std::move(callback));
PostIdleCheck();
}
void IdleWaiter::PostIdleCheck() {
FXL_DCHECK(loop_) << "No message loop set for debug features. If this is a "
"unit test rather than an integration test, consider "
"using //garnet/public/lib/gtest gtest::TestLoopFixture "
"features instead.";
if (!(callbacks_.empty() || activity_ || idle_check_pending_)) {
FXL_DCHECK(loop_->dispatcher() == async_get_default_dispatcher());
loop_->Quit();
idle_check_pending_ = true;
}
}
bool IdleWaiter::FinishIdleCheck() {
if (idle_check_pending_) {
FXL_DCHECK(loop_ && loop_->dispatcher() == async_get_default_dispatcher());
loop_->RunUntilIdle();
loop_->ResetQuit();
if (!activity_) {
for (const auto& callback : callbacks_) {
callback();
}
callbacks_.clear();
}
// Otherwise, |PostIdleCheck| will be invoked again when |activity_| is
// released.
idle_check_pending_ = false;
return true;
} else {
return false;
}
}
} // namespace util