blob: 7c895187171853ccf7e052e1ad24b365244ec10d [file] [log] [blame]
// Copyright 2019 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 "devhost-context.h"
#include <stdio.h>
#include <fbl/auto_lock.h>
#include "log.h"
namespace devmgr {
void DevhostContext::PushWorkItem(const fbl::RefPtr<zx_device_t>& dev, Callback callback) {
auto work_item = std::make_unique<WorkItem>(dev, std::move(callback));
fbl::AutoLock al(&lock_);
work_items_.push_back(std::move(work_item));
// TODO(surajmalhotra): Only signal if not being run in main devhost thread as a slight
// optimization (assuming we will run work items before going back to waiting on the port).
if (!event_waiter_->signaled()) {
event_waiter_->signal();
}
}
void DevhostContext::InternalRunWorkItems(size_t how_many_to_run) {
{
fbl::AutoLock al(&lock_);
if (event_waiter_->signaled()) {
event_waiter_->designal();
}
}
size_t work_items_run = 0;
auto keep_running = [&]() { return work_items_run < how_many_to_run || how_many_to_run == 0; };
do {
fbl::DoublyLinkedList<std::unique_ptr<WorkItem>> work_items;
{
fbl::AutoLock al(&lock_);
work_items = std::move(work_items_);
}
if (work_items.is_empty()) {
return;
}
std::unique_ptr<WorkItem> work_item;
while (keep_running() && (work_item = work_items.pop_front())) {
work_item->callback();
work_items_run++;
}
if (!work_items.is_empty()) {
fbl::AutoLock al(&lock_);
work_items_.splice(work_items_.begin(), work_items);
}
} while (keep_running());
fbl::AutoLock al(&lock_);
if (!work_items_.is_empty() && !event_waiter_->signaled()) {
event_waiter_->signal();
}
}
void DevhostContext::RunWorkItems(size_t how_many_to_run) {
std::unique_ptr<EventWaiter> event_waiter;
{
fbl::AutoLock al(&lock_);
ZX_DEBUG_ASSERT(event_waiter_ != nullptr);
if (work_items_.is_empty()) {
return;
}
event_waiter = event_waiter_->Cancel();
}
InternalRunWorkItems(how_many_to_run);
EventWaiter::BeginWait(std::move(event_waiter), loop_.dispatcher());
}
zx_status_t DevhostContext::SetupEventWaiter() {
zx::event event;
if (zx_status_t status = zx::event::create(0, &event); status != ZX_OK) {
return status;
}
// TODO(surajmalhotra): Tune this value.
constexpr uint32_t kBatchSize = 5;
auto event_waiter = std::make_unique<EventWaiter>(std::move(event),
[this]() { InternalRunWorkItems(kBatchSize); });
{
fbl::AutoLock al(&lock_);
event_waiter_ = event_waiter.get();
}
return EventWaiter::BeginWait(std::move(event_waiter), loop_.dispatcher());
}
void DevhostContext::EventWaiter::HandleEvent(std::unique_ptr<EventWaiter> event_waiter,
async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status,
const zx_packet_signal_t* signal) {
if (status != ZX_OK) {
log(ERROR, "devhost: event waiter error: %d\n", status);
return;
}
if (signal->observed & ZX_USER_SIGNAL_0) {
event_waiter->InvokeCallback();
BeginWait(std::move(event_waiter), dispatcher);
} else {
printf("%s: invalid signals %x\n", __func__, signal->observed);
abort();
}
}
} // namespace devmgr