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

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