blob: caf433e3aab7b70bad64ce3a03b5bb1376eac4b4 [file] [log] [blame]
// Copyright 2017 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 "lib/fsl/tasks/fd_waiter.h"
#include "lib/fxl/logging.h"
#include <lib/async/default.h>
#include <zircon/errors.h>
namespace fsl {
FDWaiter::FDWaiter(async_dispatcher_t* dispatcher)
: dispatcher_(dispatcher), io_(nullptr) {
FXL_DCHECK(dispatcher_);
}
FDWaiter::~FDWaiter() {
if (io_) {
Cancel();
}
FXL_DCHECK(!io_);
}
bool FDWaiter::Wait(Callback callback, int fd, uint32_t events) {
FXL_DCHECK(!io_);
io_ = fdio_unsafe_fd_to_io(fd);
if (!io_) {
return false;
}
zx_handle_t handle = ZX_HANDLE_INVALID;
zx_signals_t signals = ZX_SIGNAL_NONE;
fdio_unsafe_wait_begin(io_, events, &handle, &signals);
if (handle == ZX_HANDLE_INVALID) {
Release();
return false;
}
wait_.set_object(handle);
wait_.set_trigger(signals);
zx_status_t status = wait_.Begin(dispatcher_);
if (status != ZX_OK) {
Release();
return false;
}
// Last to prevent re-entrancy from the move constructor of the callback.
callback_ = std::move(callback);
return true;
}
void FDWaiter::Release() {
FXL_DCHECK(io_);
fdio_unsafe_release(io_);
io_ = nullptr;
}
void FDWaiter::Cancel() {
if (io_) {
wait_.Cancel();
Release();
// Last to prevent re-entrancy from the destructor of the callback.
callback_ = Callback();
}
}
void FDWaiter::Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal_t* signal) {
FXL_DCHECK(io_);
uint32_t events = 0;
if (status == ZX_OK) {
fdio_unsafe_wait_end(io_, signal->observed, &events);
}
Callback callback = std::move(callback_);
Release();
// Last to prevent re-entrancy from the callback.
callback(status, events);
}
} // namespace fsl