[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