• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 namespace LIBC_NAMESPACE {
15 namespace file {
16 
17 enum 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.
from_stream(::FILE * f)27 LIBC_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.
to_stream(uintptr_t f)38 LIBC_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 
50 template <uint16_t opcode>
write_impl(::FILE * file,const void * data,size_t size)51 LIBC_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(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 
write(::FILE * f,const void * data,size_t size)69 LIBC_INLINE uint64_t write(::FILE *f, const void *data, size_t size) {
70   if (f == stdout)
71     return write_impl<RPC_WRITE_TO_STDOUT>(f, data, size);
72   else if (f == stderr)
73     return write_impl<RPC_WRITE_TO_STDERR>(f, data, size);
74   else
75     return write_impl<RPC_WRITE_TO_STREAM>(f, data, size);
76 }
77 
read_from_stream(::FILE * file,void * buf,size_t size)78 LIBC_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([=](rpc::Buffer *buffer) {
83     buffer->data[0] = size;
84     buffer->data[1] = from_stream(file);
85   });
86   port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; });
87   port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
88   port.close();
89   return ret;
90 }
91 
read(::FILE * f,void * data,size_t size)92 LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) {
93   return read_from_stream(f, data, size);
94 }
95 
96 } // namespace file
97 } // namespace LIBC_NAMESPACE
98