blob: 736c6b9924dfe83562575dc41e7fbd582d681a28 [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 "src/lib/storage/vfs/cpp/journal/background_executor.h"
#include <threads.h>
#include <zircon/assert.h>
#include <zircon/threads.h>
namespace fs {
BackgroundExecutor::~BackgroundExecutor() {
{
std::lock_guard lock(lock_);
// If the "always running" task had suspended, this completes it.
terminate_.reset();
// If the "always running" task has not suspended, this advises it to shut itself down.
should_terminate_ = true;
}
int result = thrd_join(thrd_, nullptr);
ZX_DEBUG_ASSERT(result == thrd_success);
}
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 =
fpromise::make_promise([this](fpromise::context& context) mutable -> fpromise::result<> {
std::lock_guard 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 fpromise::ok();
}
// Suspend the task, never to actually return. When the BackgroundExecutor destructor runs,
// this suspended task will be destroyed.
terminate_ = context.suspend_task();
return fpromise::pending();
});
executor_.schedule_task(std::move(work));
int rc = thrd_create_with_name(
&thrd_,
[](void* ctx) {
reinterpret_cast<BackgroundExecutor*>(ctx)->executor_.run();
return 0;
},
this, "journal-thread");
ZX_ASSERT_MSG(rc == thrd_success, "Failed to create journal background executor thread: %d", rc);
}
} // namespace fs