1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <lib/async/cpp/wait.h>
6
7namespace async {
8
9WaitBase::WaitBase(zx_handle_t object, zx_signals_t trigger, async_wait_handler_t* handler)
10    : wait_{{ASYNC_STATE_INIT}, handler, object, trigger} {}
11
12WaitBase::~WaitBase() {
13    if (dispatcher_) {
14        // Failure to cancel here may result in a dangling pointer...
15        zx_status_t status = async_cancel_wait(dispatcher_, &wait_);
16        ZX_ASSERT_MSG(status == ZX_OK, "status=%d", status);
17    }
18}
19
20zx_status_t WaitBase::Begin(async_dispatcher_t* dispatcher) {
21    if (dispatcher_)
22        return ZX_ERR_ALREADY_EXISTS;
23
24    dispatcher_ = dispatcher;
25    zx_status_t status = async_begin_wait(dispatcher, &wait_);
26    if (status != ZX_OK) {
27        dispatcher_ = nullptr;
28    }
29    return status;
30}
31
32zx_status_t WaitBase::Cancel() {
33    if (!dispatcher_)
34        return ZX_ERR_NOT_FOUND;
35
36    async_dispatcher_t* dispatcher = dispatcher_;
37    dispatcher_ = nullptr;
38
39    zx_status_t status = async_cancel_wait(dispatcher, &wait_);
40    // |dispatcher| is required to be single-threaded, Cancel() is
41    // only supposed to be called on |dispatcher|'s thread, and
42    // we verified that the wait was pending before calling
43    // async_cancel_wait(). Assuming that |dispatcher| never queues
44    // a wait, |wait_| must have been pending with |dispatcher|.
45    ZX_DEBUG_ASSERT(status != ZX_ERR_NOT_FOUND);
46    return status;
47}
48
49Wait::Wait(zx_handle_t object, zx_signals_t trigger, Handler handler)
50    : WaitBase(object, trigger, &Wait::CallHandler), handler_(fbl::move(handler)) {}
51
52Wait::~Wait() = default;
53
54void Wait::CallHandler(async_dispatcher_t* dispatcher, async_wait_t* wait,
55                       zx_status_t status, const zx_packet_signal_t* signal) {
56    auto self = Dispatch<Wait>(wait);
57    self->handler_(dispatcher, self, status, signal);
58}
59
60} // namespace async
61