blob: a7aa3165b5566382f99a95b8ecde2b93ea5e84db [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 "src/lib/fsl/tasks/fd_waiter.h"
#include <lib/async/default.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/errors.h>
namespace fsl {
FDWaiter::FDWaiter(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher), io_(nullptr) {
FX_DCHECK(dispatcher_);
}
FDWaiter::~FDWaiter() {
if (io_) {
Cancel();
}
FX_DCHECK(!io_);
}
bool FDWaiter::Wait(Callback callback, int fd, uint32_t events) {
std::lock_guard<std::mutex> guard(mutex_);
FX_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) {
ReleaseLocked();
return false;
}
wait_.set_object(handle);
wait_.set_trigger(signals);
zx_status_t status = wait_.Begin(dispatcher_);
if (status != ZX_OK) {
ReleaseLocked();
return false;
}
callback_ = std::move(callback);
return true;
}
void FDWaiter::ReleaseLocked() {
FX_DCHECK(io_);
fdio_unsafe_release(io_);
io_ = nullptr;
}
void FDWaiter::Cancel() {
// Callback's destructor may ultimately call back into this object (e.g. to Cancel()) so take care
// to avoid destroying any Callbacks while holding the lock.
Callback to_be_destroyed;
std::lock_guard<std::mutex> guard(mutex_);
if (io_) {
wait_.Cancel();
ReleaseLocked();
to_be_destroyed = std::move(callback_);
}
}
void FDWaiter::Handler(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
Callback callback;
uint32_t events = 0;
{
std::lock_guard<std::mutex> guard(mutex_);
FX_DCHECK(io_);
if (status == ZX_OK) {
fdio_unsafe_wait_end(io_, signal->observed, &events);
}
callback = std::move(callback_);
ReleaseLocked();
}
callback(status, events);
}
} // namespace fsl