blob: 317b55404e496f0114f76d8bd214b4151626dcf7 [file] [log] [blame]
// Copyright 2023 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 <lib/async/cpp/time.h>
#include <lib/async/task.h>
#include <lib/async_patterns/cpp/task_scope.h>
#include <zircon/assert.h>
#include <mutex>
namespace async_patterns {
namespace {
constexpr char kTaskQueueThreadSafetyDescription[] = "|async_patterns::TaskQueue| is thread-unsafe";
} // namespace
TaskScope::TaskScope(async_dispatcher_t* dispatcher)
: dispatcher_(dispatcher),
checker_(dispatcher, kTaskQueueThreadSafetyDescription),
queue_(dispatcher, kTaskQueueThreadSafetyDescription) {}
TaskScope::~TaskScope() {
std::scoped_lock lock{checker_};
stopped_ = true;
queue_.Stop();
list_node_t* node = nullptr;
list_node_t* temp_node = nullptr;
list_for_every_safe(&delayed_task_list_, node, temp_node) {
auto* task = static_cast<DelayedTask*>(node);
zx_status_t status = async_cancel_task(dispatcher_, task);
ZX_DEBUG_ASSERT(status == ZX_OK);
RemoveDelayedTaskLocked(task);
}
ZX_ASSERT(list_is_empty(&delayed_task_list_));
}
TaskScope::DelayedTask::DelayedTask(TaskScope* owner)
: list_node_t(LIST_INITIAL_CLEARED_VALUE),
async_task_t{{ASYNC_STATE_INIT}, &DelayedTask::Handler, ZX_TIME_INFINITE_PAST},
owner_(owner) {}
bool TaskScope::DelayedTask::Post(async_dispatcher_t* dispatcher, zx::time deadline) {
async_task_t::deadline = deadline.get();
return async_post_task(dispatcher, this) == ZX_OK;
}
void TaskScope::DelayedTask::Handler(async_dispatcher_t* dispatcher, async_task_t* task,
zx_status_t status) {
auto* self = static_cast<DelayedTask*>(task);
if (status == ZX_OK) {
self->Run();
}
self->owner_->RemoveDelayedTask(self);
}
void TaskScope::PostImpl(std::unique_ptr<internal::Task> task) {
std::scoped_lock lock{checker_};
if (stopped_) {
return;
}
queue_.Add(std::move(task));
}
void TaskScope::PostImpl(std::unique_ptr<DelayedTask> task, zx::duration delay) {
zx::time deadline = async::Now(dispatcher_) + delay;
PostImpl(std::move(task), deadline);
}
void TaskScope::PostImpl(std::unique_ptr<DelayedTask> task, zx::time deadline) {
std::scoped_lock lock{checker_};
if (stopped_) {
return;
}
if (!task->Post(dispatcher_, deadline)) {
return;
}
list_add_tail(&delayed_task_list_, task.release());
}
void TaskScope::RemoveDelayedTask(DelayedTask* task) {
std::scoped_lock lock{checker_};
RemoveDelayedTaskLocked(task);
}
// NOLINTNEXTLINE(readability-convert-member-functions-to-static): for thread safety annotations
void TaskScope::RemoveDelayedTaskLocked(DelayedTask* task) {
list_delete(task);
delete task;
}
} // namespace async_patterns