blob: 80067aeca6108cc9b764130aaae595a1d24ce1df [file] [log] [blame]
// 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 "vmo_case.h"
#include <fidl/test.ipc/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/vmo.h>
#include <zircon/assert.h>
void VmoCase::send(zx::channel chan, Timing* cur_timing) {
ZX_ASSERT(chan.is_valid());
std::string message = std::string(config_.message_size, 'a');
start_barrier_.arrive_and_wait();
{
Timer t(&cur_timing->send_duration);
fidl::ClientEnd<test_ipc::VmoSender> client_end(std::move(chan));
fidl::WireSyncClient client(std::move(client_end));
size_t to_send = config_.messages_to_send;
while (to_send > 0) {
size_t this_batch = std::min(to_send, config_.batch_size * config_.per_vmo_batch);
to_send -= this_batch;
std::vector<zx::vmo> vmos;
size_t left_in_this_vmo = config_.per_vmo_batch;
size_t offset = 0;
zx::vmo vmo;
for (size_t i = 0; i < this_batch; ++i) {
if (left_in_this_vmo == 0) {
ZX_ASSERT(vmo.set_property(ZX_PROP_VMO_CONTENT_SIZE, &offset, sizeof(offset)) == ZX_OK);
vmos.emplace_back(std::move(vmo));
vmo = zx::vmo();
left_in_this_vmo = config_.per_vmo_batch;
offset = 0;
}
if (!vmo.is_valid()) {
ZX_ASSERT(zx::vmo::create(message.size() * config_.per_vmo_batch, 0, &vmo) == ZX_OK);
}
vmo.write(message.data(), offset, message.size());
offset += message.size();
left_in_this_vmo -= 1;
}
if (vmo.is_valid()) {
ZX_ASSERT(vmo.set_property(ZX_PROP_VMO_CONTENT_SIZE, &offset, sizeof(offset)) == ZX_OK);
vmos.push_back(std::move(vmo));
}
auto ret = client->Send(fidl::VectorView<zx::vmo>::FromExternal(vmos));
if (!ret.ok()) {
FX_LOGS(ERROR) << "Failed to send VMO: " << ret.status_string();
std::terminate();
}
}
}
stop_barrier_.arrive_and_wait();
}
namespace {
class VmoReceiver : public fidl::WireServer<test_ipc::VmoSender> {
using SendCompleter = ::fidl::internal::WireCompleter<test_ipc::VmoSender::Send>;
public:
explicit VmoReceiver(size_t* received, size_t message_size, size_t per_vmo_batch)
: received_bytes_(received), message_size_(message_size), per_vmo_batch_(per_vmo_batch) {}
void Send(::test_ipc::wire::VmoSenderSendRequest* request,
SendCompleter::Sync& completer) override {
for (zx::vmo& vmo : request->vmos) {
ZX_ASSERT(vmo.is_valid());
size_t size;
vmo.get_property(ZX_PROP_VMO_CONTENT_SIZE, &size, sizeof(size));
ZX_ASSERT(size <= message_size_ * per_vmo_batch_);
std::vector<uint8_t> buffer;
buffer.resize(size);
ZX_ASSERT(vmo.read(buffer.data(), 0, size) == ZX_OK);
*received_bytes_ += size;
}
completer.Reply();
}
private:
size_t* received_bytes_;
size_t message_size_;
size_t per_vmo_batch_;
};
} // namespace
void VmoCase::recv(zx::channel chan, Timing* cur_timing) {
ZX_ASSERT(chan.is_valid());
start_barrier_.arrive_and_wait();
{
Timer t(&cur_timing->recv_duration);
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
fidl::ServerEnd<test_ipc::VmoSender> server_end(std::move(chan));
size_t received_bytes = 0;
VmoReceiver receiver(&received_bytes, config_.message_size, config_.per_vmo_batch);
auto binding =
fidl::BindServer(loop.dispatcher(), std::move(server_end), &receiver,
[&loop](VmoReceiver*, fidl::UnbindInfo info,
fidl::ServerEnd<test_ipc::VmoSender> server_end) { loop.Quit(); });
loop.Run();
ZX_ASSERT(received_bytes == config_.messages_to_send * config_.message_size);
}
stop_barrier_.arrive_and_wait();
}