You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.9 KiB
124 lines
3.9 KiB
// Copyright 2017 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/task.h>
|
|
|
|
#include <lib/async/cpp/time.h>
|
|
#include <zircon/assert.h>
|
|
|
|
#include <utility>
|
|
|
|
namespace async {
|
|
namespace internal {
|
|
|
|
struct RetainedTask : public async_task_t {
|
|
RetainedTask(fit::closure handler, zx::time deadline)
|
|
: async_task_t{{ASYNC_STATE_INIT}, &RetainedTask::Handler, deadline.get()},
|
|
handler(static_cast<fit::closure&&>(handler)) {}
|
|
|
|
fit::closure handler;
|
|
|
|
static void Handler(async_dispatcher_t* dispatcher, async_task_t* task, zx_status_t status) {
|
|
auto self = static_cast<RetainedTask*>(task);
|
|
if (status == ZX_OK)
|
|
self->handler();
|
|
delete self;
|
|
}
|
|
};
|
|
|
|
} // namespace internal
|
|
|
|
zx_status_t PostTask(async_dispatcher_t* dispatcher, fit::closure handler) {
|
|
return PostTaskForTime(dispatcher, static_cast<fit::closure&&>(handler), async::Now(dispatcher));
|
|
}
|
|
|
|
zx_status_t PostDelayedTask(async_dispatcher_t* dispatcher, fit::closure handler,
|
|
zx::duration delay) {
|
|
return PostTaskForTime(dispatcher, static_cast<fit::closure&&>(handler),
|
|
async::Now(dispatcher) + delay);
|
|
}
|
|
|
|
zx_status_t PostTaskForTime(async_dispatcher_t* dispatcher, fit::closure handler,
|
|
zx::time deadline) {
|
|
auto* task = new internal::RetainedTask(static_cast<fit::closure&&>(handler), deadline);
|
|
zx_status_t status = async_post_task(dispatcher, task);
|
|
if (status != ZX_OK)
|
|
delete task;
|
|
return status;
|
|
}
|
|
|
|
TaskBase::TaskBase(async_task_handler_t* handler)
|
|
: task_{{ASYNC_STATE_INIT}, handler, ZX_TIME_INFINITE} {}
|
|
|
|
TaskBase::~TaskBase() {
|
|
if (dispatcher_) {
|
|
// Failure to cancel here may result in a dangling pointer...
|
|
zx_status_t status = async_cancel_task(dispatcher_, &task_);
|
|
ZX_ASSERT_MSG(status == ZX_OK, "status=%d", status);
|
|
}
|
|
}
|
|
|
|
zx_status_t TaskBase::Post(async_dispatcher_t* dispatcher) {
|
|
return PostForTime(dispatcher, async::Now(dispatcher));
|
|
}
|
|
|
|
zx_status_t TaskBase::PostDelayed(async_dispatcher_t* dispatcher, zx::duration delay) {
|
|
return PostForTime(dispatcher, async::Now(dispatcher) + delay);
|
|
}
|
|
|
|
zx_status_t TaskBase::PostForTime(async_dispatcher_t* dispatcher, zx::time deadline) {
|
|
if (dispatcher_)
|
|
return ZX_ERR_ALREADY_EXISTS;
|
|
|
|
dispatcher_ = dispatcher;
|
|
task_.deadline = deadline.get();
|
|
zx_status_t status = async_post_task(dispatcher, &task_);
|
|
if (status != ZX_OK) {
|
|
dispatcher_ = nullptr;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
zx_status_t TaskBase::Cancel() {
|
|
if (!dispatcher_)
|
|
return ZX_ERR_NOT_FOUND;
|
|
|
|
async_dispatcher_t* dispatcher = dispatcher_;
|
|
dispatcher_ = nullptr;
|
|
|
|
zx_status_t status = async_cancel_task(dispatcher, &task_);
|
|
// |dispatcher| is required to be single-threaded, Cancel() is
|
|
// only supposed to be called on |dispatcher|'s thread, and we
|
|
// verified that the task was pending before calling
|
|
// async_cancel_task(). Assuming that |dispatcher| does not yield
|
|
// between removing the task and invoking the task's handler,
|
|
// |task_| must have been pending with |dispatcher|.
|
|
ZX_DEBUG_ASSERT(status != ZX_ERR_NOT_FOUND);
|
|
return status;
|
|
}
|
|
|
|
Task::Task(Handler handler) : TaskBase(&Task::CallHandler), handler_(std::move(handler)) {}
|
|
|
|
Task::~Task() = default;
|
|
|
|
void Task::CallHandler(async_dispatcher_t* dispatcher, async_task_t* task, zx_status_t status) {
|
|
auto self = Dispatch<Task>(task);
|
|
self->handler_(dispatcher, self, status);
|
|
}
|
|
|
|
TaskClosure::TaskClosure(fit::closure handler)
|
|
: TaskBase(&TaskClosure::CallHandler), handler_(std::move(handler)) {}
|
|
|
|
TaskClosure::~TaskClosure() = default;
|
|
|
|
void TaskClosure::CallHandler(async_dispatcher_t* dispatcher, async_task_t* task,
|
|
zx_status_t status) {
|
|
auto self = Dispatch<TaskClosure>(task); // must do this if status is not ok
|
|
if (status == ZX_OK) {
|
|
self->handler_();
|
|
}
|
|
}
|
|
|
|
} // namespace async
|