blob: c7395faa9dea96b7b33312be8cc5d8083251b470 [file] [log] [blame]
// Copyright 2019 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 "garnet/lib/debug_ipc/helper/event_handlers.h"
#include <lib/async-loop/loop.h>
#include <lib/async/default.h>
#include "lib/fxl/logging.h"
#include "garnet/lib/debug_ipc/helper/message_loop_async.h"
#include "garnet/lib/debug_ipc/helper/zx_status.h"
namespace debug_ipc {
// SignalHandler ---------------------------------------------------------------
SignalHandler::SignalHandler() = default;
SignalHandler::SignalHandler(int id, zx_handle_t object, zx_signals_t signals)
: watch_info_id_(id), handle_(std::make_unique<async_wait_t>()) {
*handle_ = {}; // Need to zero it out.
handle_->handler = Handler;
handle_->object = object;
handle_->trigger = signals;
WaitForSignals();
}
SignalHandler::~SignalHandler() {
if (handle_) {
async_wait_t* wait = handle_.get();
auto status = async_cancel_wait(async_get_default_dispatcher(), wait);
FXL_DCHECK(status == ZX_OK) << "Got: " << ZxStatusToString(status);
}
}
SignalHandler::SignalHandler(SignalHandler&&) = default;
SignalHandler& SignalHandler::operator=(SignalHandler&&) = default;
void SignalHandler::WaitForSignals() const {
async_wait_t* wait = handle_.get();
zx_status_t status = async_begin_wait(async_get_default_dispatcher(), wait);
FXL_DCHECK(status == ZX_OK);
}
void SignalHandler::Handler(async_dispatcher_t*, async_wait_t* wait,
zx_status_t status,
const zx_packet_signal_t* signal) {
FXL_DCHECK(status == ZX_OK);
auto* loop = MessageLoopAsync::Current();
FXL_DCHECK(loop);
// Search for the AsyncHandle that triggered this signal.
auto handler_it = loop->signal_handlers().find(wait);
FXL_DCHECK(handler_it != loop->signal_handlers().end());
const SignalHandler& signal_handler = handler_it->second;
int watch_info_id = signal_handler.watch_info_id();
auto* watch_info = loop->FindWatchInfo(watch_info_id);
FXL_DCHECK(watch_info);
switch (watch_info->type) {
case WatchType::kFdio:
signal_handler.WaitForSignals();
loop->OnFdioSignal(watch_info_id, *watch_info, signal->observed);
break;
case WatchType::kSocket:
signal_handler.WaitForSignals();
loop->OnSocketSignal(watch_info_id, *watch_info, signal->observed);
break;
case WatchType::kTask:
FXL_DCHECK(watch_info_id == kTaskSignalKey);
signal_handler.WaitForSignals();
loop->CheckAndProcessPendingTasks();
break;
case WatchType::kProcessExceptions:
loop->OnProcessTerminated(*watch_info, signal->observed);
break;
case WatchType::kJobExceptions:
FXL_NOTREACHED();
}
}
// ExceptionHandler ------------------------------------------------------------
ExceptionHandler::ExceptionHandler() = default;
ExceptionHandler::ExceptionHandler(int id, zx_handle_t object, uint32_t options)
: watch_info_id_(id), handle_(std::make_unique<async_exception_t>()) {
*handle_ = {}; // Need to zero it out.
handle_->state = ASYNC_STATE_INIT;
handle_->handler = Handler;
handle_->task = object;
handle_->options = options;
zx_status_t status =
async_bind_exception_port(async_get_default_dispatcher(), handle_.get());
FXL_DCHECK(status == ZX_OK)
<< "Expected ZX_OK, got " << ZxStatusToString(status);
}
ExceptionHandler::~ExceptionHandler() {
if (handle_) {
async_unbind_exception_port(async_get_default_dispatcher(), handle_.get());
}
}
// Copy constructors are implicitly deleted by unique_ptr
ExceptionHandler::ExceptionHandler(ExceptionHandler&&) = default;
ExceptionHandler& ExceptionHandler::operator=(ExceptionHandler&&) = default;
void ExceptionHandler::Handler(async_dispatcher_t*,
async_exception_t* exception, zx_status_t status,
const zx_port_packet_t* packet) {
if (status == ZX_ERR_CANCELED) {
return;
}
FXL_DCHECK(status == ZX_OK)
<< "Unexpected status: " << ZxStatusToString(status);
auto* loop = MessageLoopAsync::Current();
FXL_DCHECK(loop);
// We search for the AsyncHandle that triggered this signal.
auto handler_it = loop->exception_handlers().find(exception);
FXL_DCHECK(handler_it != loop->exception_handlers().end());
const ExceptionHandler& exception_handler = handler_it->second;
// We copy the packet in order to pass in the key.
auto new_packet = *packet;
new_packet.key = exception_handler.watch_info_id_;
loop->HandleException(exception_handler, std::move(new_packet));
}
} // namespace debug_ipc