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