1 // Copyright 2018 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/exception.h>
6 
7 #include <utility>
8 
9 namespace async {
10 
ExceptionBase(zx_handle_t task,uint32_t options,async_exception_handler_t * handler)11 ExceptionBase::ExceptionBase(zx_handle_t task, uint32_t options,
12                              async_exception_handler_t* handler)
13     : exception_{{ASYNC_STATE_INIT}, handler, task, options} {
14     ZX_DEBUG_ASSERT(handler);
15 }
16 
~ExceptionBase()17 ExceptionBase::~ExceptionBase() {
18     if (dispatcher_) {
19         // Failure to unbind here may result in a dangling pointer...
20         zx_status_t status = async_unbind_exception_port(dispatcher_, &exception_);
21         ZX_ASSERT_MSG(status == ZX_OK, "status=%d", status);
22     }
23 }
24 
Bind(async_dispatcher_t * dispatcher)25 zx_status_t ExceptionBase::Bind(async_dispatcher_t* dispatcher) {
26     if (dispatcher_)
27         return ZX_ERR_ALREADY_EXISTS;
28 
29     dispatcher_ = dispatcher;
30     zx_status_t status = async_bind_exception_port(dispatcher, &exception_);
31     if (status != ZX_OK) {
32         dispatcher_ = nullptr;
33     }
34     return status;
35 }
36 
Unbind()37 zx_status_t ExceptionBase::Unbind() {
38     if (!dispatcher_)
39         return ZX_ERR_NOT_FOUND;
40 
41     async_dispatcher_t* dispatcher = dispatcher_;
42     dispatcher_ = nullptr;
43 
44     zx_status_t status = async_unbind_exception_port(dispatcher, &exception_);
45     // |dispatcher| is required to be single-threaded, Unbind() is
46     // only supposed to be called on |dispatcher|'s thread, and
47     // we verified that the port was bound before calling
48     // async_unbind_exception_port().
49     ZX_DEBUG_ASSERT(status != ZX_ERR_NOT_FOUND);
50     return status;
51 }
52 
Resume(zx_handle_t task,uint32_t options)53 zx_status_t ExceptionBase::Resume(zx_handle_t task, uint32_t options) {
54     if (!dispatcher_)
55         return ZX_ERR_NOT_FOUND;
56 
57     return async_resume_from_exception(dispatcher_, &exception_, task, options);
58 }
59 
Exception(zx_handle_t task,uint32_t options,Handler handler)60 Exception::Exception(zx_handle_t task, uint32_t options,
61                      Handler handler)
62     : ExceptionBase(task, options, &Exception::CallHandler),
63       handler_(std::move(handler)) {}
64 
65 Exception::~Exception() = default;
66 
CallHandler(async_dispatcher_t * dispatcher,async_exception_t * exception,zx_status_t status,const zx_port_packet_t * report)67 void Exception::CallHandler(async_dispatcher_t* dispatcher,
68                             async_exception_t* exception,
69                             zx_status_t status,
70                             const zx_port_packet_t* report) {
71     auto self = Dispatch<Exception>(exception);
72     self->handler_(dispatcher, self, status, report);
73 }
74 
75 } // namespace async
76