//===--- GPU helper functions for file I/O using RPC ----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "src/__support/RPC/rpc_client.h" #include "src/__support/macros/config.h" #include "src/string/string_utils.h" #include "hdr/stdio_macros.h" // For stdin/out/err #include "hdr/types/FILE.h" namespace LIBC_NAMESPACE_DECL { namespace file { enum Stream { File = 0, Stdin = 1, Stdout = 2, Stderr = 3, }; // When copying between the client and server we need to indicate if this is one // of the special streams. We do this by enocding the low order bits of the // pointer to indicate if we need to use the host's standard stream. LIBC_INLINE uintptr_t from_stream(::FILE *f) { if (f == stdin) return reinterpret_cast(f) | Stdin; if (f == stdout) return reinterpret_cast(f) | Stdout; if (f == stderr) return reinterpret_cast(f) | Stderr; return reinterpret_cast(f); } // Get the associated stream out of an encoded number. LIBC_INLINE ::FILE *to_stream(uintptr_t f) { ::FILE *stream = reinterpret_cast(f & ~0x3ull); Stream type = static_cast(f & 0x3ull); if (type == Stdin) return stdin; if (type == Stdout) return stdout; if (type == Stderr) return stderr; return stream; } template LIBC_INLINE uint64_t write_impl(::FILE *file, const void *data, size_t size) { uint64_t ret = 0; rpc::Client::Port port = rpc::client.open(); if constexpr (opcode == RPC_WRITE_TO_STREAM) { port.send([&](rpc::Buffer *buffer, uint32_t) { buffer->data[0] = reinterpret_cast(file); }); } port.send_n(data, size); port.recv([&](rpc::Buffer *buffer, uint32_t) { ret = reinterpret_cast(buffer->data)[0]; }); port.close(); return ret; } LIBC_INLINE uint64_t write(::FILE *f, const void *data, size_t size) { if (f == stdout) return write_impl(f, data, size); else if (f == stderr) return write_impl(f, data, size); else return write_impl(f, data, size); } LIBC_INLINE uint64_t read_from_stream(::FILE *file, void *buf, size_t size) { uint64_t ret = 0; uint64_t recv_size; rpc::Client::Port port = rpc::client.open(); port.send([=](rpc::Buffer *buffer, uint32_t) { buffer->data[0] = size; buffer->data[1] = from_stream(file); }); port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; }); port.recv([&](rpc::Buffer *buffer, uint32_t) { ret = buffer->data[0]; }); port.close(); return ret; } LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) { return read_from_stream(f, data, size); } } // namespace file } // namespace LIBC_NAMESPACE_DECL