blob: d2d0c66c79d43aa7aac202fe3ebe53fb677fec68 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "object/wait_signal_observer.h"
#include <assert.h>
#include <kernel/event.h>
#include <ktl/atomic.h>
#include <object/dispatcher.h>
#include <object/handle.h>
WaitSignalObserver::~WaitSignalObserver() { DEBUG_ASSERT(!dispatcher_); }
zx_status_t WaitSignalObserver::Begin(Event* event, Handle* handle, zx_signals_t watched_signals) {
canary_.Assert();
DEBUG_ASSERT(!dispatcher_);
event_ = event;
dispatcher_ = handle->dispatcher();
// Wait for one of |watched_signals| to become active.
//
// Note that |watched_signals| may be 0, in which case we won't receive
// a callback, but will remain queued until |End| is called.
zx_status_t status = handle->dispatcher()->AddObserver(this, handle, watched_signals);
if (status != ZX_OK) {
dispatcher_.reset();
return status;
}
return ZX_OK;
}
zx_signals_t WaitSignalObserver::End() {
canary_.Assert();
DEBUG_ASSERT(dispatcher_);
// Otherwise, remove this observer from the dispatcher's observer list.
zx_signals_t signals;
bool was_removed = dispatcher_->RemoveObserver(this, &signals);
dispatcher_.reset();
// If |was_removed| is false, it means a callback was fired and |final_signal_state| has
// a value.
if (!was_removed) {
return final_signal_state_.load(ktl::memory_order_acquire);
}
// Otherwise, return the set of signals at the point of removal.
return signals;
}
void WaitSignalObserver::OnMatch(zx_signals_t signals) {
canary_.Assert();
// Save the signal state, and wake our waiter.
final_signal_state_.store(signals, ktl::memory_order_release);
event_->Signal();
}
void WaitSignalObserver::OnCancel(zx_signals_t signals) {
canary_.Assert();
// Save the signal state, and wake our waiter.
final_signal_state_.store(signals | ZX_SIGNAL_HANDLE_CLOSED, ktl::memory_order_release);
event_->Signal(ZX_ERR_CANCELED);
}