aboutsummaryrefslogtreecommitdiff
path: root/libc/src/stdio/gpu/file.h
blob: 102c6c601b30bee454cbd5aa4f5caeb8d3ca02a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//===--- GPU helper functions for file I/O using RPC ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "hdr/stdio_macros.h" // For stdin/out/err
#include "hdr/types/FILE.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"
#include "src/__support/macros/attributes.h"

namespace LIBC_NAMESPACE_DECL {
namespace file {

enum Stream {
  File = 0,
  Stdin = 1,
  Stdout = 2,
  Stderr = 3,
};

// When copying between the client and server we need to indicate if this is one
// of the special streams. We do this by enocding the low order bits of the
// pointer to indicate if we need to use the host's standard stream.
LIBC_INLINE uintptr_t from_stream(::FILE *f) {
  if (f == stdin)
    return reinterpret_cast<uintptr_t>(f) | Stdin;
  if (f == stdout)
    return reinterpret_cast<uintptr_t>(f) | Stdout;
  if (f == stderr)
    return reinterpret_cast<uintptr_t>(f) | Stderr;
  return reinterpret_cast<uintptr_t>(f);
}

// Get the associated stream out of an encoded number.
LIBC_INLINE ::FILE *to_stream(uintptr_t f) {
  ::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull);
  Stream type = static_cast<Stream>(f & 0x3ull);
  if (type == Stdin)
    return stdin;
  if (type == Stdout)
    return stdout;
  if (type == Stderr)
    return stderr;
  return stream;
}

template <uint32_t opcode>
LIBC_INLINE uint64_t write_impl(::FILE *file, const void *data, size_t size) {
  uint64_t ret = 0;
  rpc::Client::Port port = rpc::client.open<opcode>();

  if constexpr (opcode == LIBC_WRITE_TO_STREAM) {
    port.send([&](rpc::Buffer *buffer, uint32_t) {
      buffer->data[0] = reinterpret_cast<uintptr_t>(file);
    });
  }

  port.send_n(data, size);
  port.recv([&](rpc::Buffer *buffer, uint32_t) {
    ret = reinterpret_cast<uint64_t *>(buffer->data)[0];
  });
  port.close();
  return ret;
}

LIBC_INLINE uint64_t write(::FILE *f, const void *data, size_t size) {
  if (f == stdout)
    return write_impl<LIBC_WRITE_TO_STDOUT>(f, data, size);
  else if (f == stderr)
    return write_impl<LIBC_WRITE_TO_STDERR>(f, data, size);
  else
    return write_impl<LIBC_WRITE_TO_STREAM>(f, data, size);
}

LIBC_INLINE uint64_t read_from_stream(::FILE *file, void *buf, size_t size) {
  uint64_t ret = 0;
  uint64_t recv_size;
  rpc::Client::Port port = rpc::client.open<LIBC_READ_FROM_STREAM>();
  port.send([=](rpc::Buffer *buffer, uint32_t) {
    buffer->data[0] = size;
    buffer->data[1] = from_stream(file);
  });
  port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; });
  port.recv([&](rpc::Buffer *buffer, uint32_t) { ret = buffer->data[0]; });
  port.close();
  return ret;
}

LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) {
  return read_from_stream(f, data, size);
}

} // namespace file
} // namespace LIBC_NAMESPACE_DECL