1 //===--- GPU helper functions for file I/O using RPC ----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/__support/RPC/rpc_client.h" 10 #include "src/__support/macros/config.h" 11 #include "src/string/string_utils.h" 12 13 #include "hdr/stdio_macros.h" // For stdin/out/err 14 #include "hdr/types/FILE.h" 15 16 namespace LIBC_NAMESPACE_DECL { 17 namespace file { 18 19 enum Stream { 20 File = 0, 21 Stdin = 1, 22 Stdout = 2, 23 Stderr = 3, 24 }; 25 26 // When copying between the client and server we need to indicate if this is one 27 // of the special streams. We do this by enocding the low order bits of the 28 // pointer to indicate if we need to use the host's standard stream. 29 LIBC_INLINE uintptr_t from_stream(::FILE *f) { 30 if (f == stdin) 31 return reinterpret_cast<uintptr_t>(f) | Stdin; 32 if (f == stdout) 33 return reinterpret_cast<uintptr_t>(f) | Stdout; 34 if (f == stderr) 35 return reinterpret_cast<uintptr_t>(f) | Stderr; 36 return reinterpret_cast<uintptr_t>(f); 37 } 38 39 // Get the associated stream out of an encoded number. 40 LIBC_INLINE ::FILE *to_stream(uintptr_t f) { 41 ::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull); 42 Stream type = static_cast<Stream>(f & 0x3ull); 43 if (type == Stdin) 44 return stdin; 45 if (type == Stdout) 46 return stdout; 47 if (type == Stderr) 48 return stderr; 49 return stream; 50 } 51 52 template <uint32_t opcode> 53 LIBC_INLINE uint64_t write_impl(::FILE *file, const void *data, size_t size) { 54 uint64_t ret = 0; 55 rpc::Client::Port port = rpc::client.open<opcode>(); 56 57 if constexpr (opcode == LIBC_WRITE_TO_STREAM) { 58 port.send([&](rpc::Buffer *buffer, uint32_t) { 59 buffer->data[0] = reinterpret_cast<uintptr_t>(file); 60 }); 61 } 62 63 port.send_n(data, size); 64 port.recv([&](rpc::Buffer *buffer, uint32_t) { 65 ret = reinterpret_cast<uint64_t *>(buffer->data)[0]; 66 }); 67 port.close(); 68 return ret; 69 } 70 71 LIBC_INLINE uint64_t write(::FILE *f, const void *data, size_t size) { 72 if (f == stdout) 73 return write_impl<LIBC_WRITE_TO_STDOUT>(f, data, size); 74 else if (f == stderr) 75 return write_impl<LIBC_WRITE_TO_STDERR>(f, data, size); 76 else 77 return write_impl<LIBC_WRITE_TO_STREAM>(f, data, size); 78 } 79 80 LIBC_INLINE uint64_t read_from_stream(::FILE *file, void *buf, size_t size) { 81 uint64_t ret = 0; 82 uint64_t recv_size; 83 rpc::Client::Port port = rpc::client.open<LIBC_READ_FROM_STREAM>(); 84 port.send([=](rpc::Buffer *buffer, uint32_t) { 85 buffer->data[0] = size; 86 buffer->data[1] = from_stream(file); 87 }); 88 port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; }); 89 port.recv([&](rpc::Buffer *buffer, uint32_t) { ret = buffer->data[0]; }); 90 port.close(); 91 return ret; 92 } 93 94 LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) { 95 return read_from_stream(f, data, size); 96 } 97 98 } // namespace file 99 } // namespace LIBC_NAMESPACE_DECL 100