[libc-commits] [libc] c850ea1 - [libc] Support fopen / fclose on the GPU
Joseph Huber via libc-commits
libc-commits at lists.llvm.org
Wed Jul 5 16:32:07 PDT 2023
Author: Joseph Huber
Date: 2023-07-05T18:31:58-05:00
New Revision: c850ea1498733d4f54d501d56157270d83a4244c
URL: https://github.com/llvm/llvm-project/commit/c850ea1498733d4f54d501d56157270d83a4244c
DIFF: https://github.com/llvm/llvm-project/commit/c850ea1498733d4f54d501d56157270d83a4244c.diff
LOG: [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
Added:
libc/test/src/stdio/fopen_test.cpp
Modified:
libc/config/gpu/entrypoints.txt
libc/docs/gpu/support.rst
libc/include/llvm-libc-types/rpc_opcodes_t.h
libc/src/__support/File/gpu/file.cpp
libc/test/src/stdio/CMakeLists.txt
libc/utils/gpu/server/rpc_server.cpp
Removed:
################################################################################
diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index e3ac3d2db0a87d..4316f8a57a8731 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -90,6 +90,8 @@ set(TARGET_LIBC_ENTRYPOINTS
# stdio.h entrypoints
libc.src.stdio.puts
libc.src.stdio.fputs
+ libc.src.stdio.fclose
+ libc.src.stdio.fopen
libc.src.stdio.stdin
libc.src.stdio.stdout
libc.src.stdio.stderr
diff --git a/libc/docs/gpu/support.rst b/libc/docs/gpu/support.rst
index 40ab5d5bd83547..bc94c833efeb70 100644
--- a/libc/docs/gpu/support.rst
+++ b/libc/docs/gpu/support.rst
@@ -124,4 +124,6 @@ Function Name Available RPC Required
============= ========= ============
puts |check| |check|
fputs |check| |check|
+fclose |check| |check|
+fopen |check| |check|
============= ========= ============
diff --git a/libc/include/llvm-libc-types/rpc_opcodes_t.h b/libc/include/llvm-libc-types/rpc_opcodes_t.h
index 8a2ad5bda75422..f53bda7d3a8568 100644
--- a/libc/include/llvm-libc-types/rpc_opcodes_t.h
+++ b/libc/include/llvm-libc-types/rpc_opcodes_t.h
@@ -15,11 +15,15 @@ typedef enum : unsigned short {
RPC_WRITE_TO_STDOUT = 2,
RPC_WRITE_TO_STDERR = 3,
RPC_WRITE_TO_STREAM = 4,
- RPC_MALLOC = 5,
- RPC_FREE = 6,
- RPC_TEST_INCREMENT = 7,
- RPC_TEST_INTERFACE = 8,
- RPC_TEST_STREAM = 9,
+ RPC_OPEN_FILE = 5,
+ RPC_CLOSE_FILE = 6,
+ RPC_MALLOC = 7,
+ RPC_FREE = 8,
+ // TODO: Move these out of here and handle then with custom handlers in the
+ // loader.
+ RPC_TEST_INCREMENT = 1000,
+ RPC_TEST_INTERFACE = 1001,
+ RPC_TEST_STREAM = 1002,
} rpc_opcode_t;
#endif // __LLVM_LIBC_TYPES_RPC_OPCODE_H__
diff --git a/libc/src/__support/File/gpu/file.cpp b/libc/src/__support/File/gpu/file.cpp
index 11554e692578e7..d474e388b6d9fc 100644
--- a/libc/src/__support/File/gpu/file.cpp
+++ b/libc/src/__support/File/gpu/file.cpp
@@ -8,8 +8,10 @@
#include "src/__support/File/file.h"
+#include "llvm-libc-types/rpc_opcodes_t.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/errno/libc_errno.h" // For error macros
+#include "src/string/string_utils.h"
#include <stdio.h>
@@ -18,6 +20,7 @@ namespace __llvm_libc {
namespace {
FileIOResult write_func(File *, const void *, size_t);
+int close_func(File *);
} // namespace
@@ -26,8 +29,8 @@ class GPUFile : public File {
public:
constexpr GPUFile(uintptr_t file, File::ModeFlags modeflags)
- : File(&write_func, nullptr, nullptr, nullptr, nullptr, 0, _IONBF, false,
- modeflags),
+ : File(&write_func, nullptr, nullptr, &close_func, nullptr, 0, _IONBF,
+ false, modeflags),
file(file) {}
uintptr_t get_file() const { return file; }
@@ -85,8 +88,42 @@ FileIOResult write_func(File *f, const void *data, size_t size) {
return ret;
}
+int close_func(File *file) {
+ int ret = 0;
+ GPUFile *gpu_file = reinterpret_cast<GPUFile *>(file);
+ rpc::Client::Port port = rpc::client.open<RPC_CLOSE_FILE>();
+ port.send_and_recv(
+ [=](rpc::Buffer *buffer) { buffer->data[0] = gpu_file->get_file(); },
+ [&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
+ port.close();
+
+ return ret;
+}
+
} // namespace
+void *ptr;
+
+ErrorOr<File *> openfile(const char *path, const char *mode) {
+ auto modeflags = File::mode_flags(mode);
+ if (modeflags == 0)
+ return Error(EINVAL);
+
+ uintptr_t file;
+ rpc::Client::Port port = rpc::client.open<RPC_OPEN_FILE>();
+ port.send_n(path, internal::string_length(path) + 1);
+ port.send_and_recv(
+ [=](rpc::Buffer *buffer) {
+ inline_memcpy(buffer->data, mode, internal::string_length(mode) + 1);
+ },
+ [&](rpc::Buffer *buffer) { file = buffer->data[0]; });
+ port.close();
+
+ static GPUFile gpu_file(0, 0);
+ gpu_file = GPUFile(file, modeflags);
+ return &gpu_file;
+}
+
static GPUFile StdIn(0UL, File::ModeFlags(File::OpenMode::READ));
File *stdin = &StdIn;
diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index c138f35cb57f4c..7b28a9c8a9b166 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -222,6 +222,18 @@ add_libc_test(
libc.src.stdio.fputs
)
+add_libc_test(
+ fopen_test
+ SUITE
+ libc_stdio_unittests
+ SRCS
+ fopen_test.cpp
+ DEPENDS
+ libc.src.stdio.fputs
+ libc.src.stdio.fclose
+ libc.src.stdio.fopen
+)
+
add_libc_unittest(
putc_test
SUITE
@@ -329,6 +341,9 @@ add_libc_unittest(
libc.src.stdio.setvbuf
)
+# Create an output directory for any temporary test files.
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/testdata)
+
if(LIBC_TARGET_ARCHITECTURE_IS_GPU)
return()
endif()
diff --git a/libc/test/src/stdio/fopen_test.cpp b/libc/test/src/stdio/fopen_test.cpp
new file mode 100644
index 00000000000000..09a283ab919c41
--- /dev/null
+++ b/libc/test/src/stdio/fopen_test.cpp
@@ -0,0 +1,27 @@
+//===-- Unittests for fopen / fclose --------------------------------------===//
+//
+// 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 "src/__support/File/file.h"
+#include "src/stdio/fclose.h"
+#include "src/stdio/fopen.h"
+#include "src/stdio/fputs.h"
+
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcFOpenTest, PrintToFile) {
+ int result;
+
+ FILE *file = __llvm_libc::fopen("./testdata/test_data.txt", "w");
+ ASSERT_FALSE(file == nullptr);
+
+ constexpr char another[] = "A simple string written to a file\n";
+ result = __llvm_libc::fputs(another, file);
+ EXPECT_GE(result, 0);
+
+ ASSERT_EQ(0, __llvm_libc::fclose(file));
+}
diff --git a/libc/utils/gpu/server/rpc_server.cpp b/libc/utils/gpu/server/rpc_server.cpp
index ac7dca6232cebe..6540e38a8f7cf8 100644
--- a/libc/utils/gpu/server/rpc_server.cpp
+++ b/libc/utils/gpu/server/rpc_server.cpp
@@ -101,6 +101,24 @@ struct Server {
}
break;
}
+ case RPC_OPEN_FILE: {
+ uint64_t sizes[rpc::MAX_LANE_SIZE] = {0};
+ void *paths[rpc::MAX_LANE_SIZE] = {nullptr};
+ port->recv_n(paths, sizes, [&](uint64_t size) { return new char[size]; });
+ port->recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
+ FILE *file = fopen(reinterpret_cast<char *>(paths[id]),
+ reinterpret_cast<char *>(buffer->data));
+ buffer->data[0] = reinterpret_cast<uintptr_t>(file);
+ });
+ break;
+ }
+ case RPC_CLOSE_FILE: {
+ port->recv_and_send([&](rpc::Buffer *buffer, uint32_t id) {
+ FILE *file = reinterpret_cast<FILE *>(buffer->data[0]);
+ buffer->data[0] = fclose(file);
+ });
+ break;
+ }
case RPC_EXIT: {
// Send a response to the client to signal that we are ready to exit.
port->recv_and_send([](rpc::Buffer *) {});
More information about the libc-commits
mailing list