blob: 264b79eea4f121c9e78d8e1899314a325843899e [file] [log] [blame]
// Copyright 2018 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/bin/guest/vmm/virtio_queue_waiter.h"
#include <lib/fxl/logging.h>
VirtioQueueWaiter::VirtioQueueWaiter(async_dispatcher_t* dispatcher,
VirtioQueue* queue, Handler handler)
: wait_(this, queue->event(), VirtioQueue::SIGNAL_QUEUE_AVAIL),
dispatcher_(dispatcher),
queue_(queue),
handler_(std::move(handler)) {}
VirtioQueueWaiter::~VirtioQueueWaiter() { Cancel(); }
zx_status_t VirtioQueueWaiter::Begin() {
zx_status_t status = ZX_OK;
std::lock_guard<std::mutex> lock(mutex_);
if (!pending_) {
status = wait_.Begin(dispatcher_);
if (status == ZX_OK) {
pending_ = true;
}
}
return status;
}
void VirtioQueueWaiter::Cancel() {
std::lock_guard<std::mutex> lock(mutex_);
if (pending_) {
wait_.Cancel();
pending_ = false;
}
}
void VirtioQueueWaiter::WaitHandler(async_dispatcher_t* dispatcher,
async::WaitBase* wait, zx_status_t status,
const zx_packet_signal_t* signal) {
uint16_t index = 0;
{
std::lock_guard<std::mutex> lock(mutex_);
if (!pending_) {
return;
}
// Only invoke the handler if we can get a descriptor.
if (status == ZX_OK) {
status = queue_->NextAvail(&index);
if (status == ZX_ERR_SHOULD_WAIT) {
status = wait->Begin(dispatcher);
if (status == ZX_OK) {
return;
}
}
}
pending_ = false;
}
handler_(status, index);
}