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