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