forked from niftich/magenta
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[async] Add RAII helpers for waits and tasks.
This makes the API a bit more convenient to use. Fixed an inconsistency in the handling of cancelation errors. We were previously checking for MX_ERR_BAD_STATE which can't happen during cancelation. Fixed some minor formatting inconsistencies introduced by the mxtl->fbl rename. Added some clarification around thread-safety. Change-Id: If273a42eea2b869d63c79e47782c28fade339c92
- Loading branch information
Jeff Brown
committed
Sep 8, 2017
1 parent
f9bf251
commit 56fa14e
Showing
15 changed files
with
544 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// 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 <async/auto_task.h> | ||
|
||
#include <magenta/assert.h> | ||
|
||
namespace async { | ||
|
||
AutoTask::AutoTask(async_t* async, mx_time_t deadline, uint32_t flags) | ||
: async_task_t{{ASYNC_STATE_INIT}, &AutoTask::CallHandler, deadline, flags, {}}, | ||
async_(async) { | ||
MX_DEBUG_ASSERT(async_); | ||
} | ||
|
||
AutoTask::~AutoTask() { | ||
Cancel(); | ||
} | ||
|
||
mx_status_t AutoTask::Post() { | ||
MX_DEBUG_ASSERT(!pending_); | ||
|
||
mx_status_t status = async_post_task(async_, this); | ||
if (status == MX_OK) | ||
pending_ = true; | ||
|
||
return status; | ||
} | ||
|
||
void AutoTask::Cancel() { | ||
if (!pending_) | ||
return; | ||
|
||
mx_status_t status = async_cancel_task(async_, this); | ||
MX_DEBUG_ASSERT_MSG(status == MX_OK, "status=%d", status); | ||
|
||
pending_ = false; | ||
} | ||
|
||
async_task_result_t AutoTask::CallHandler(async_t* async, async_task_t* task, | ||
mx_status_t status) { | ||
auto self = static_cast<AutoTask*>(task); | ||
MX_DEBUG_ASSERT(self->pending_); | ||
self->pending_ = false; | ||
|
||
async_task_result_t result = self->handler_(async, status); | ||
if (result == ASYNC_TASK_REPEAT && status == MX_OK) { | ||
MX_DEBUG_ASSERT(!self->pending_); | ||
self->pending_ = true; | ||
} | ||
return result; | ||
} | ||
|
||
} // namespace async |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// 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 <async/auto_wait.h> | ||
|
||
#include <magenta/assert.h> | ||
|
||
namespace async { | ||
|
||
AutoWait::AutoWait(async_t* async, mx_handle_t object, mx_signals_t trigger, uint32_t flags) | ||
: async_wait_t{{ASYNC_STATE_INIT}, &AutoWait::CallHandler, object, trigger, flags, {}}, | ||
async_(async) { | ||
MX_DEBUG_ASSERT(async_); | ||
} | ||
|
||
AutoWait::~AutoWait() { | ||
Cancel(); | ||
} | ||
|
||
mx_status_t AutoWait::Begin() { | ||
MX_DEBUG_ASSERT(!pending_); | ||
|
||
mx_status_t status = async_begin_wait(async_, this); | ||
if (status == MX_OK) | ||
pending_ = true; | ||
|
||
return status; | ||
} | ||
|
||
void AutoWait::Cancel() { | ||
if (!pending_) | ||
return; | ||
|
||
mx_status_t status = async_cancel_wait(async_, this); | ||
MX_DEBUG_ASSERT_MSG(status == MX_OK, "status=%d", status); | ||
|
||
pending_ = false; | ||
} | ||
|
||
async_wait_result_t AutoWait::CallHandler(async_t* async, async_wait_t* wait, | ||
mx_status_t status, const mx_packet_signal_t* signal) { | ||
auto self = static_cast<AutoWait*>(wait); | ||
MX_DEBUG_ASSERT(self->pending_); | ||
self->pending_ = false; | ||
|
||
async_wait_result_t result = self->handler_(async, status, signal); | ||
if (result == ASYNC_WAIT_AGAIN && status == MX_OK) { | ||
MX_DEBUG_ASSERT(!self->pending_); | ||
self->pending_ = true; | ||
} | ||
return result; | ||
} | ||
|
||
} // namespace async |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// 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. | ||
|
||
#pragma once | ||
|
||
#include <async/task.h> | ||
|
||
#ifdef __cplusplus | ||
|
||
#include <fbl/function.h> | ||
#include <fbl/macros.h> | ||
|
||
namespace async { | ||
|
||
// C++ wrapper for a pending task which is automatically canceled when | ||
// it goes out of scope. | ||
// | ||
// This class is NOT thread-safe; it can only be used with single-threaded | ||
// asynchronous dispatchers. | ||
class AutoTask final : private async_task_t { | ||
public: | ||
// Handles execution of a posted task. | ||
// | ||
// Reports the |status| of the task. If the status is |MX_OK| then the | ||
// task ran, otherwise the task did not run. | ||
// | ||
// The result indicates whether the task should be repeated; it may | ||
// modify the task's properties (such as the deadline) before returning. | ||
// | ||
// The result must be |ASYNC_TASK_FINISHED| if |status| was not |MX_OK|. | ||
// | ||
// It is safe for the handler to destroy itself when returning |ASYNC_TASK_FINISHED|. | ||
using Handler = fbl::Function<async_task_result_t(async_t* async, | ||
mx_status_t status)>; | ||
|
||
// Initializes the properties of the task and binds it to an asynchronous | ||
// dispatcher. | ||
explicit AutoTask(async_t* async, | ||
mx_time_t deadline = MX_TIME_INFINITE, | ||
uint32_t flags = 0u); | ||
|
||
// Destroys the task. | ||
// | ||
// The task is canceled automatically if it is still pending. | ||
~AutoTask(); | ||
|
||
// Gets the asynchronous dispatcher to which this task has been bound. | ||
async_t* async() const { return async_; } | ||
|
||
// Returns true if the |Post()| was called successfully but the task has | ||
// not started execution or been canceled. | ||
bool is_pending() const { return pending_; } | ||
|
||
// Gets or sets the handler to invoke when the task becomes due. | ||
// Must be set before posting the task. | ||
const Handler& handler() const { return handler_; } | ||
void set_handler(Handler handler) { handler_ = fbl::move(handler); } | ||
|
||
// The time when the task should run. | ||
mx_time_t deadline() const { return async_task_t::deadline; } | ||
void set_deadline(mx_time_t deadline) { async_task_t::deadline = deadline; } | ||
|
||
// Valid flags: |ASYNC_FLAG_HANDLE_SHUTDOWN|. | ||
uint32_t flags() const { return async_task_t::flags; } | ||
void set_flags(uint32_t flags) { async_task_t::flags = flags; } | ||
|
||
// Posts a task to run on or after its deadline following all posted | ||
// tasks with lesser or equal deadlines. | ||
// | ||
// See |async_post_task()| for details. | ||
mx_status_t Post(); | ||
|
||
// Cancels the task. | ||
// | ||
// This method does nothing if the wait is not pending. | ||
// | ||
// See |async_cancel_task()| for details. | ||
void Cancel(); | ||
|
||
private: | ||
static async_task_result_t CallHandler(async_t* async, async_task_t* task, | ||
mx_status_t status); | ||
|
||
async_t* const async_; | ||
Handler handler_; | ||
bool pending_ = false; | ||
|
||
DISALLOW_COPY_ASSIGN_AND_MOVE(AutoTask); | ||
}; | ||
|
||
} // namespace async | ||
|
||
#endif // __cplusplus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// 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. | ||
|
||
#pragma once | ||
|
||
#include <async/wait.h> | ||
|
||
#ifdef __cplusplus | ||
|
||
#include <fbl/function.h> | ||
#include <fbl/macros.h> | ||
|
||
namespace async { | ||
|
||
// C++ wrapper for a pending wait operation which is automatically canceled | ||
// when it goes out of scope. | ||
// | ||
// This class is NOT thread-safe; it can only be used with single-threaded | ||
// asynchronous dispatchers. | ||
class AutoWait final : private async_wait_t { | ||
public: | ||
// Handles completion of asynchronous wait operations. | ||
// | ||
// Reports the |status| of the wait. If the status is |MX_OK| then |signal| | ||
// describes the signal which was received, otherwise |signal| is null. | ||
// | ||
// The result indicates whether the wait should be repeated; it may | ||
// modify the wait's properties (such as the trigger) before returning. | ||
// | ||
// The result must be |ASYNC_WAIT_FINISHED| if |status| was not |MX_OK|. | ||
// | ||
// It is safe for the handler to destroy itself when returning |ASYNC_WAIT_FINISHED|. | ||
using Handler = fbl::Function<async_wait_result_t(async_t* async, | ||
mx_status_t status, | ||
const mx_packet_signal_t* signal)>; | ||
|
||
// Initializes the properties of the wait operation and binds it to an | ||
// asynchronous dispatcher. | ||
explicit AutoWait(async_t* async, | ||
mx_handle_t object = MX_HANDLE_INVALID, | ||
mx_signals_t trigger = MX_SIGNAL_NONE, | ||
uint32_t flags = 0u); | ||
|
||
// Destroys the wait operation. | ||
// | ||
// The wait is canceled automatically if it is still pending. | ||
~AutoWait(); | ||
|
||
// Gets the asynchronous dispatcher to which this wait has been bound. | ||
async_t* async() const { return async_; } | ||
|
||
// Returns true if |Begin()| was called successfully but the wait has not | ||
// completed or been canceled. | ||
bool is_pending() const { return pending_; } | ||
|
||
// Gets or sets the handler to invoke when the wait completes. | ||
// Must be set before beginning the wait. | ||
const Handler& handler() const { return handler_; } | ||
void set_handler(Handler handler) { handler_ = fbl::move(handler); } | ||
|
||
// The object to wait for signals on. | ||
mx_handle_t object() const { return async_wait_t::object; } | ||
void set_object(mx_handle_t object) { async_wait_t::object = object; } | ||
|
||
// The set of signals to wait for. | ||
mx_signals_t trigger() const { return async_wait_t::trigger; } | ||
void set_trigger(mx_signals_t trigger) { async_wait_t::trigger = trigger; } | ||
|
||
// Valid flags: |ASYNC_FLAG_HANDLE_SHUTDOWN|. | ||
uint32_t flags() const { return async_wait_t::flags; } | ||
void set_flags(uint32_t flags) { async_wait_t::flags = flags; } | ||
|
||
// Begins asynchronously waiting for the object to receive one or more of | ||
// the trigger signals. | ||
// | ||
// This method must not be called when the wait is already pending. | ||
// | ||
// See |async_begin_wait()| for details. | ||
mx_status_t Begin(); | ||
|
||
// Cancels the wait. | ||
// | ||
// This method does nothing if the wait is not pending. | ||
// | ||
// See |async_cancel_wait()| for details. | ||
void Cancel(); | ||
|
||
private: | ||
static async_wait_result_t CallHandler(async_t* async, async_wait_t* wait, | ||
mx_status_t status, | ||
const mx_packet_signal_t* signal); | ||
|
||
async_t* const async_; | ||
Handler handler_; | ||
bool pending_ = false; | ||
|
||
DISALLOW_COPY_ASSIGN_AND_MOVE(AutoWait); | ||
}; | ||
|
||
} // namespace async | ||
|
||
#endif // __cplusplus |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.