blob: d5b6a113c59b8a59fe1aed2d1539a422c141f554 [file] [log] [blame]
// Copyright 2019 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 <blobfs/background-executor.h>
#include <zircon/assert.h>
namespace blobfs {
BackgroundExecutor::~BackgroundExecutor() {
if (thrd_.joinable()) {
{
std::lock_guard<std::mutex> lock(lock_);
// If the "always running" task had suspended, this completes it.
terminate_.reset();
// If the "always running" task has not suspened, this advises it to
// shut itself down.
should_terminate_ = true;
}
thrd_.join();
}
}
BackgroundExecutor::BackgroundExecutor() {
// Create a unit of work for the runner to munch on if no tasks are pending.
// This will ensure the invocation of |executor::run()| doesn't terminate until
// the termination task is resumed.
//
// Once the termination task is resumed, all pending tasks will be completed, and
// the runner thread will exit.
auto work = fit::make_promise([this](fit::context& context) mutable -> fit::result<> {
std::lock_guard<std::mutex> lock(lock_);
if (should_terminate_) {
// In this case, the BackgroundExecutor terminated before the runner started
// processing this unit of work. That's a quick shutdown!
//
// In this case, no one will try to resume us if we suspend, so just
// exit early.
return fit::ok();
}
// Suspend the task, never to actually return. When the BackgroundExecutor
// destructor runs, this suspended task will be destroyed.
terminate_ = context.suspend_task();
return fit::pending();
});
executor_.schedule_task(std::move(work));
thrd_ = std::thread([this] { executor_.run(); });
}
} // namespace blobfs