blob: df7213bb813fbb6afe8a126318c8b5fdf28850c9 [file] [log] [blame] [edit]
// Copyright 2020 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/drivers/misc/goldfish_control/heap.h"
#include <fidl/fuchsia.sysmem2/cpp/wire.h>
#include <lib/async-loop/default.h>
#include <lib/async-loop/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/ddk/debug.h>
#include <lib/fidl/cpp/wire/server.h>
#include <lib/fit/function.h>
#include <memory>
#include <fbl/intrusive_double_list.h>
#include "src/graphics/drivers/misc/goldfish_control/control_device.h"
namespace goldfish {
Heap::Heap(Control* control, const char* tag)
: control_(control), loop_(&kAsyncLoopConfigNoAttachToCurrentThread), tag_(tag) {
ZX_DEBUG_ASSERT(control_);
// Start server thread. Heap server must be running on a separate
// thread as sysmem might be making synchronous allocation requests
// from the main thread.
std::string thread_name = tag_ + "-thread";
loop_.StartThread(thread_name.c_str());
}
Heap::~Heap() { loop_.Shutdown(); }
void Heap::BindWithHeapProperties(zx::channel server_request,
std::unique_ptr<fidl::Arena<512>> allocator,
fuchsia_hardware_sysmem::wire::HeapProperties heap_properties) {
async::PostTask(
loop_.dispatcher(),
[server_end = fidl::ServerEnd<fuchsia_hardware_sysmem::Heap>(std::move(server_request)),
allocator = std::move(allocator), heap_properties = std::move(heap_properties),
this]() mutable {
auto binding =
fidl::BindServer(loop_.dispatcher(), std::move(server_end), this,
[](Heap* self, fidl::UnbindInfo info,
fidl::ServerEnd<fuchsia_hardware_sysmem::Heap> server_end) {
self->OnClose(info, server_end.TakeChannel());
});
auto result = fidl::WireSendEvent(binding)->OnRegister(std::move(heap_properties));
if (!result.ok()) {
zxlogf(ERROR, "[%s] OnRegister() failed: %s", tag_.c_str(),
result.FormatDescription().c_str());
}
});
}
void Heap::OnClose(fidl::UnbindInfo info, zx::channel channel) {
if (info.is_dispatcher_shutdown()) {
// The Control device Heap belongs to is already destroyed so that the
// pending wait is cancelled. In that case we don't need to remove the heap,
// instead just exit.
zxlogf(INFO, "[%s] Control device is destroyed: status: %d", tag_.c_str(), info.status());
return;
}
if (info.is_peer_closed()) {
zxlogf(INFO, "[%s] Client closed Heap connection: epitaph: %d", tag_.c_str(), info.status());
} else if (!info.is_user_initiated()) {
zxlogf(ERROR, "[%s] Channel internal error: status: %d", tag_.c_str(), info.status());
}
control_->RemoveHeap(this);
}
} // namespace goldfish