|  | // 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(); | 
|  | } |