Skip to content

Commit c850ea1

Browse files
committed
[libc] Support fopen / fclose on the GPU
This patch adds the necessary support for the fopen and fclose functions to work on the GPU via RPC. I added a new test that enables testing this with the minimal features we have on the GPU. I will update it once we have `fread` and `fwrite` to actually check the outputted strings. For now I just relied on checking manually via the outpuot temp file. Reviewed By: JonChesterfield, sivachandra Differential Revision: https://reviews.llvm.org/D154519
1 parent 7e88e26 commit c850ea1

File tree

7 files changed

+112
-7
lines changed

7 files changed

+112
-7
lines changed

libc/config/gpu/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ set(TARGET_LIBC_ENTRYPOINTS
9090
# stdio.h entrypoints
9191
libc.src.stdio.puts
9292
libc.src.stdio.fputs
93+
libc.src.stdio.fclose
94+
libc.src.stdio.fopen
9395
libc.src.stdio.stdin
9496
libc.src.stdio.stdout
9597
libc.src.stdio.stderr

libc/docs/gpu/support.rst

+2
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,6 @@ Function Name Available RPC Required
124124
============= ========= ============
125125
puts |check| |check|
126126
fputs |check| |check|
127+
fclose |check| |check|
128+
fopen |check| |check|
127129
============= ========= ============

libc/include/llvm-libc-types/rpc_opcodes_t.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ typedef enum : unsigned short {
1515
RPC_WRITE_TO_STDOUT = 2,
1616
RPC_WRITE_TO_STDERR = 3,
1717
RPC_WRITE_TO_STREAM = 4,
18-
RPC_MALLOC = 5,
19-
RPC_FREE = 6,
20-
RPC_TEST_INCREMENT = 7,
21-
RPC_TEST_INTERFACE = 8,
22-
RPC_TEST_STREAM = 9,
18+
RPC_OPEN_FILE = 5,
19+
RPC_CLOSE_FILE = 6,
20+
RPC_MALLOC = 7,
21+
RPC_FREE = 8,
22+
// TODO: Move these out of here and handle then with custom handlers in the
23+
// loader.
24+
RPC_TEST_INCREMENT = 1000,
25+
RPC_TEST_INTERFACE = 1001,
26+
RPC_TEST_STREAM = 1002,
2327
} rpc_opcode_t;
2428

2529
#endif // __LLVM_LIBC_TYPES_RPC_OPCODE_H__

libc/src/__support/File/gpu/file.cpp

+39-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
#include "src/__support/File/file.h"
1010

11+
#include "llvm-libc-types/rpc_opcodes_t.h"
1112
#include "src/__support/RPC/rpc_client.h"
1213
#include "src/errno/libc_errno.h" // For error macros
14+
#include "src/string/string_utils.h"
1315

1416
#include <stdio.h>
1517

@@ -18,6 +20,7 @@ namespace __llvm_libc {
1820
namespace {
1921

2022
FileIOResult write_func(File *, const void *, size_t);
23+
int close_func(File *);
2124

2225
} // namespace
2326

@@ -26,8 +29,8 @@ class GPUFile : public File {
2629

2730
public:
2831
constexpr GPUFile(uintptr_t file, File::ModeFlags modeflags)
29-
: File(&write_func, nullptr, nullptr, nullptr, nullptr, 0, _IONBF, false,
30-
modeflags),
32+
: File(&write_func, nullptr, nullptr, &close_func, nullptr, 0, _IONBF,
33+
false, modeflags),
3134
file(file) {}
3235

3336
uintptr_t get_file() const { return file; }
@@ -85,8 +88,42 @@ FileIOResult write_func(File *f, const void *data, size_t size) {
8588
return ret;
8689
}
8790

91+
int close_func(File *file) {
92+
int ret = 0;
93+
GPUFile *gpu_file = reinterpret_cast<GPUFile *>(file);
94+
rpc::Client::Port port = rpc::client.open<RPC_CLOSE_FILE>();
95+
port.send_and_recv(
96+
[=](rpc::Buffer *buffer) { buffer->data[0] = gpu_file->get_file(); },
97+
[&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
98+
port.close();
99+
100+
return ret;
101+
}
102+
88103
} // namespace
89104

105+
void *ptr;
106+
107+
ErrorOr<File *> openfile(const char *path, const char *mode) {
108+
auto modeflags = File::mode_flags(mode);
109+
if (modeflags == 0)
110+
return Error(EINVAL);
111+
112+
uintptr_t file;
113+
rpc::Client::Port port = rpc::client.open<RPC_OPEN_FILE>();
114+
port.send_n(path, internal::string_length(path) + 1);
115+
port.send_and_recv(
116+
[=](rpc::Buffer *buffer) {
117+
inline_memcpy(buffer->data, mode, internal::string_length(mode) + 1);
118+
},
119+
[&](rpc::Buffer *buffer) { file = buffer->data[0]; });
120+
port.close();
121+
122+
static GPUFile gpu_file(0, 0);
123+
gpu_file = GPUFile(file, modeflags);
124+
return &gpu_file;
125+
}
126+
90127
static GPUFile StdIn(0UL, File::ModeFlags(File::OpenMode::READ));
91128
File *stdin = &StdIn;
92129

libc/test/src/stdio/CMakeLists.txt

+15
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ add_libc_test(
222222
libc.src.stdio.fputs
223223
)
224224

225+
add_libc_test(
226+
fopen_test
227+
SUITE
228+
libc_stdio_unittests
229+
SRCS
230+
fopen_test.cpp
231+
DEPENDS
232+
libc.src.stdio.fputs
233+
libc.src.stdio.fclose
234+
libc.src.stdio.fopen
235+
)
236+
225237
add_libc_unittest(
226238
putc_test
227239
SUITE
@@ -329,6 +341,9 @@ add_libc_unittest(
329341
libc.src.stdio.setvbuf
330342
)
331343

344+
# Create an output directory for any temporary test files.
345+
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/testdata)
346+
332347
if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
333348
return()
334349
endif()

libc/test/src/stdio/fopen_test.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===-- Unittests for fopen / fclose --------------------------------------===//
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/File/file.h"
10+
#include "src/stdio/fclose.h"
11+
#include "src/stdio/fopen.h"
12+
#include "src/stdio/fputs.h"
13+
14+
#include "test/UnitTest/Test.h"
15+
16+
TEST(LlvmLibcFOpenTest, PrintToFile) {
17+
int result;
18+
19+
FILE *file = __llvm_libc::fopen("./testdata/test_data.txt", "w");
20+
ASSERT_FALSE(file == nullptr);
21+
22+
constexpr char another[] = "A simple string written to a file\n";
23+
result = __llvm_libc::fputs(another, file);
24+
EXPECT_GE(result, 0);
25+
26+
ASSERT_EQ(0, __llvm_libc::fclose(file));
27+
}

libc/utils/gpu/server/rpc_server.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ struct Server {
101101
}
102102
break;
103103
}
104+
case RPC_OPEN_FILE: {
105+
uint64_t sizes[rpc::MAX_LANE_SIZE] = {0};
106+
void *paths[rpc::MAX_LANE_SIZE] = {nullptr};
107+
port->recv_n(paths, sizes, [&](uint64_t size) { return new char[size]; });
108+
port->recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
109+
FILE *file = fopen(reinterpret_cast<char *>(paths[id]),
110+
reinterpret_cast<char *>(buffer->data));
111+
buffer->data[0] = reinterpret_cast<uintptr_t>(file);
112+
});
113+
break;
114+
}
115+
case RPC_CLOSE_FILE: {
116+
port->recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
117+
FILE *file = reinterpret_cast<FILE *>(buffer->data[0]);
118+
buffer->data[0] = fclose(file);
119+
});
120+
break;
121+
}
104122
case RPC_EXIT: {
105123
// Send a response to the client to signal that we are ready to exit.
106124
port->recv_and_send([](rpc::Buffer *) {});

0 commit comments

Comments
 (0)