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

source code of libc/src/stdio/gpu/file.h