blob: 387b95a2d17399d097f5ee7bbbd286f305166bcd [file] [log] [blame]
// Copyright 2021 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 "signal-coordinator.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/time.h>
#include <zircon/errors.h>
#include <zircon/status.h>
namespace fuzzing {
SignalCoordinator::~SignalCoordinator() { Reset(); }
void SignalCoordinator::CreateImpl(zx::eventpair* out) {
Reset();
zx_status_t status = zx::eventpair::create(0, &paired_, out);
if (status != ZX_OK) {
FX_LOGS(FATAL) << "Failed to create eventpair: " << zx_status_get_string(status);
}
}
void SignalCoordinator::PairImpl(zx::eventpair paired) {
Reset();
if (!paired.is_valid()) {
FX_LOGS(FATAL) << "Received bad eventpair.";
}
paired_ = std::move(paired);
}
zx_signals_t SignalCoordinator::WaitOne() {
zx_signals_t observed;
zx_status_t status = paired_.wait_one(ZX_USER_SIGNAL_ALL | ZX_EVENTPAIR_PEER_CLOSED,
zx::time::infinite(), &observed);
// Check if another thread reset |paired_| before the call to |wait_one|, or during it.
if (status == ZX_ERR_BAD_HANDLE || status == ZX_ERR_CANCELED) {
return ZX_EVENTPAIR_PEER_CLOSED;
}
if (status != ZX_OK) {
FX_LOGS(FATAL) << "Failed to wait for eventpair peer: " << zx_status_get_string(status);
}
// Check if the other end reset the connection.
if (observed & ZX_EVENTPAIR_PEER_CLOSED) {
return ZX_EVENTPAIR_PEER_CLOSED;
}
// Check if another thread reset |paired_| before the call to |signal|.
status = paired_.signal(observed, 0);
if (status == ZX_ERR_BAD_HANDLE) {
return ZX_EVENTPAIR_PEER_CLOSED;
}
if (status != ZX_OK) {
FX_LOGS(FATAL) << "Failed to clear eventpair: " << zx_status_get_string(status);
}
return observed;
}
bool SignalCoordinator::SignalPeer(Signal signal) {
// Check if another thread reset |paired_| before the call to |signal_peer|, or if the other end
// reset the connection.
zx_status_t status = paired_.signal_peer(0, signal);
if (status == ZX_ERR_BAD_HANDLE || status == ZX_ERR_PEER_CLOSED) {
return false;
}
if (status != ZX_OK) {
FX_LOGS(FATAL) << "Failed to signal eventpair peer: " << zx_status_get_string(status);
}
return true;
}
void SignalCoordinator::Reset() {
paired_.reset();
Join();
}
void SignalCoordinator::Join() {
if (wait_loop_.joinable()) {
wait_loop_.join();
}
}
} // namespace fuzzing