blob: be129652fd4fb9357f99ddbfb620dfc57d17865d [file] [log] [blame] [edit]
// Copyright 2024 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/graphics/display/lib/driver-framework-migration-utils/dispatcher/loop-backed-dispatcher.h"
#include <lib/async-loop/loop.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <lib/zx/result.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/threads.h>
#include <string>
#include <fbl/alloc_checker.h>
namespace display {
namespace {
const async_loop_config_t kIrqHandlerAsyncLoopConfig = [] {
async_loop_config_t loop_config = kAsyncLoopConfigNeverAttachToThread;
loop_config.irq_support = true;
return loop_config;
}();
} // namespace
// static
zx::result<std::unique_ptr<Dispatcher>> LoopBackedDispatcher::Create(
zx_device_t* device, std::string_view thread_name, std::string_view scheduler_role) {
ZX_DEBUG_ASSERT(device != nullptr);
ZX_DEBUG_ASSERT(!thread_name.empty());
fbl::AllocChecker alloc_checker;
auto dispatcher = fbl::make_unique_checked<LoopBackedDispatcher>(&alloc_checker);
if (!alloc_checker.check()) {
return zx::error(ZX_ERR_NO_MEMORY);
}
zx::result<> start_thread_result = dispatcher->StartThread(thread_name);
if (start_thread_result.is_error()) {
zxlogf(ERROR, "Failed to start async Loop dispatcher thread: %s",
start_thread_result.status_string());
return start_thread_result.take_error();
}
if (!scheduler_role.empty()) {
zx::result<> set_scheduler_role_result =
dispatcher->SetThreadSchedulerRole(scheduler_role, device);
if (set_scheduler_role_result.is_error()) {
zxlogf(WARNING, "Failed to set scheduler role: %s",
set_scheduler_role_result.status_string());
}
}
return zx::ok(std::move(dispatcher));
}
// static
zx::result<std::unique_ptr<Dispatcher>> LoopBackedDispatcher::Create(std::string_view thread_name) {
ZX_DEBUG_ASSERT(!thread_name.empty());
fbl::AllocChecker alloc_checker;
auto dispatcher = fbl::make_unique_checked<LoopBackedDispatcher>(&alloc_checker);
if (!alloc_checker.check()) {
return zx::error(ZX_ERR_NO_MEMORY);
}
zx::result<> start_thread_result = dispatcher->StartThread(thread_name);
if (start_thread_result.is_error()) {
zxlogf(ERROR, "Failed to start async Loop dispatcher thread: %s",
start_thread_result.status_string());
return start_thread_result.take_error();
}
return zx::ok(std::move(dispatcher));
}
LoopBackedDispatcher::LoopBackedDispatcher() : loop_(&kIrqHandlerAsyncLoopConfig) {}
LoopBackedDispatcher::~LoopBackedDispatcher() { loop_.Shutdown(); }
zx::result<> LoopBackedDispatcher::StartThread(std::string_view thread_name) {
ZX_DEBUG_ASSERT(!thread_name.empty());
// `std::string_view` is not null-terminated, so we need to copy it to a
// null-terminated string to use in `Loop::StartThread()`.
std::string thread_name_string(thread_name);
return zx::make_result(loop_.StartThread(thread_name_string.c_str(), &loop_thread_));
}
zx::result<> LoopBackedDispatcher::SetThreadSchedulerRole(std::string_view scheduler_role,
zx_device_t* device) {
zx_handle_t zx_thread = thrd_get_zx_handle(loop_thread_);
return zx::make_result(
device_set_profile_by_role(device, zx_thread, scheduler_role.data(), scheduler_role.size()));
}
} // namespace display