blob: b7b828f8c577f1c694dd5f7fdb1d0ef0ec660bf3 [file]
// Copyright 2025 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 <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/media/codec_impl/log.h>
#include <zircon/assert.h>
#include <zircon/status.h>
#include <zircon/threads.h>
#include "src/media/lib/codec_impl/dispatcher.h"
namespace codec_impl {
class DispatcherViaAsyncLoop : public Dispatcher {
public:
explicit DispatcherViaAsyncLoop(const char* name, std::string_view scheduler_role)
: loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
thrd_t thrd{};
zx_status_t start_thread_result = loop_.StartThread(name, &thrd);
if (start_thread_result != ZX_OK) {
LOG(WARN, "loop_.StartThread() failed: %s", zx_status_get_string(start_thread_result));
ZX_DEBUG_ASSERT(thrd_ == thrd_t{});
return;
}
thrd_.store(thrd, std::memory_order_relaxed);
ZX_DEBUG_ASSERT(thrd_ != thrd_t{});
if (!scheduler_role.empty()) {
// probably YAGNI; DFv1 drivers can just keep using CoreCodecSetStreamControlProfile.
//
// If needed, would involve plumbing zx_device_t device and:
//
// zx::thread zx_thread(thrd_get_zx_handle(thrd_));
//
// device_set_profile_by_role(device, zx_thread, scheduler_role.data(),
// scheduler_role.size());
//
// or possibly equivalent/newer/better way(s).
LOG(WARN, "DispatcherViaAsyncLoop doesn't support scheduler_role so far");
// intentionally keep going
}
}
bool IsStarted() {
// Constructor already complained to the log.
return thrd_.load(std::memory_order_relaxed) != thrd_t{};
}
~DispatcherViaAsyncLoop() {
// caller must Join() first (unless !IsStarted() immediately after construction)
ZX_ASSERT(!IsStarted());
}
bool IsCurrent() override { return thrd_current() == thrd_.load(std::memory_order_relaxed); }
async_dispatcher_t* dispatcher() override {
ZX_DEBUG_ASSERT(IsStarted());
return loop_.dispatcher();
}
void QuitAsync() override {
ZX_DEBUG_ASSERT(IsStarted());
loop_.Quit();
}
void Join() override {
ZX_DEBUG_ASSERT(IsStarted());
loop_.Shutdown();
loop_.JoinThreads();
thrd_ = thrd_t{};
}
std::optional<thrd_t> maybe_thrd() override { return thrd_; }
private:
async::Loop loop_;
std::atomic<thrd_t> thrd_;
};
// static
//
// name is for naming the async::Loop thread or fdf::Dispatcher
std::unique_ptr<Dispatcher> DispatcherFactory::Create(const char* name,
std::string_view scheduler_role) {
auto result =
std::unique_ptr<DispatcherViaAsyncLoop>(new DispatcherViaAsyncLoop(name, scheduler_role));
if (!result->IsStarted()) {
// ~result
return nullptr;
}
return result;
}
} // namespace codec_impl