diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt --- a/libc/config/gpu/entrypoints.txt +++ b/libc/config/gpu/entrypoints.txt @@ -83,6 +83,7 @@ # stdio.h entrypoints libc.src.stdio.puts libc.src.stdio.fputs + libc.src.stdio.fread libc.src.stdio.fclose libc.src.stdio.fopen libc.src.stdio.stdin diff --git a/libc/include/llvm-libc-types/rpc_opcodes_t.h b/libc/include/llvm-libc-types/rpc_opcodes_t.h --- a/libc/include/llvm-libc-types/rpc_opcodes_t.h +++ b/libc/include/llvm-libc-types/rpc_opcodes_t.h @@ -15,11 +15,13 @@ RPC_WRITE_TO_STDOUT = 2, RPC_WRITE_TO_STDERR = 3, RPC_WRITE_TO_STREAM = 4, - RPC_OPEN_FILE = 5, - RPC_CLOSE_FILE = 6, - RPC_MALLOC = 7, - RPC_FREE = 8, - RPC_HOST_CALL = 9, + RPC_READ_FROM_STDIN = 5, + RPC_READ_FROM_STREAM = 6, + RPC_OPEN_FILE = 7, + RPC_CLOSE_FILE = 8, + RPC_MALLOC = 9, + RPC_FREE = 10, + RPC_HOST_CALL = 11, } 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 --- a/libc/src/__support/File/gpu/file.cpp +++ b/libc/src/__support/File/gpu/file.cpp @@ -19,6 +19,7 @@ namespace { FileIOResult write_func(File *, const void *, size_t); +FileIOResult read_func(File *, void *, size_t); int close_func(File *); } // namespace @@ -28,7 +29,7 @@ public: constexpr GPUFile(uintptr_t file, File::ModeFlags modeflags) - : File(&write_func, nullptr, nullptr, &close_func, nullptr, 0, _IONBF, + : File(&write_func, &read_func, nullptr, &close_func, nullptr, 0, _IONBF, false, modeflags), file(file) {} @@ -87,6 +88,46 @@ return ret; } +int read_from_stdin(void *buf, size_t size) { + int ret = 0; + uint64_t recv_size; + rpc::Client::Port port = rpc::client.open(); + port.send([=](rpc::Buffer *buffer) { buffer->data[0] = size; }); + port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; }); + port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; }); + port.close(); + return ret; +} + +int read_from_stream(uintptr_t file, void *buf, size_t size) { + int ret = 0; + uint64_t recv_size; + // TODO: For large sizes being written to a pointer in global memory, we + // should be able to initiate a H2D memcpy via a separate RPC call at high + // bandwidth. + rpc::Client::Port port = rpc::client.open(); + port.send([=](rpc::Buffer *buffer) { + buffer->data[0] = size; + buffer->data[1] = file; + }); + port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; }); + port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; }); + port.close(); + return ret; +} + +FileIOResult read_func(File *f, void *buf, size_t size) { + auto *gpu_file = reinterpret_cast(f); + int ret = 0; + if (gpu_file == stdin) + ret = read_from_stdin(buf, size); + else + ret = read_from_stream(gpu_file->get_file(), buf, size); + if (ret < 0) + return {0, -ret}; + return ret; +} + int close_func(File *file) { int ret = 0; GPUFile *gpu_file = reinterpret_cast(file); diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -227,6 +227,7 @@ SRCS fopen_test.cpp DEPENDS + libc.src.stdio.fread libc.src.stdio.fputs libc.src.stdio.fclose libc.src.stdio.fopen diff --git a/libc/test/src/stdio/fopen_test.cpp b/libc/test/src/stdio/fopen_test.cpp --- a/libc/test/src/stdio/fopen_test.cpp +++ b/libc/test/src/stdio/fopen_test.cpp @@ -10,6 +10,7 @@ #include "src/stdio/fclose.h" #include "src/stdio/fopen.h" #include "src/stdio/fputs.h" +#include "src/stdio/fread.h" #include "test/UnitTest/Test.h" @@ -19,9 +20,20 @@ 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); + static constexpr char STRING[] = "A simple string written to a file\n"; + result = __llvm_libc::fputs(STRING, file); EXPECT_GE(result, 0); ASSERT_EQ(0, __llvm_libc::fclose(file)); + + FILE *new_file = __llvm_libc::fopen("./testdata/test_data.txt", "r"); + ASSERT_FALSE(new_file == nullptr); + + static char data[64] = {0}; + ASSERT_EQ(__llvm_libc::fread(data, 1, sizeof(STRING) - 1, new_file), + sizeof(STRING) - 1); + data[sizeof(STRING) - 1] = '\0'; + ASSERT_STREQ(data, STRING); + + ASSERT_EQ(0, __llvm_libc::fclose(new_file)); } diff --git a/libc/utils/gpu/server/rpc_server.cpp b/libc/utils/gpu/server/rpc_server.cpp --- a/libc/utils/gpu/server/rpc_server.cpp +++ b/libc/utils/gpu/server/rpc_server.cpp @@ -104,6 +104,26 @@ } break; } + case RPC_READ_FROM_STREAM: + case RPC_READ_FROM_STDIN: { + uint64_t sizes[rpc::MAX_LANE_SIZE] = {0}; + void *data[rpc::MAX_LANE_SIZE] = {nullptr}; + uint64_t rets[rpc::MAX_LANE_SIZE] = {0}; + port->recv([&](rpc::Buffer *buffer, uint32_t id) { + sizes[id] = buffer->data[0]; + data[id] = new char[sizes[id]]; + FILE *file = port->get_opcode() == RPC_READ_FROM_STREAM + ? reinterpret_cast(buffer->data[1]) + : stdin; + rets[id] = fread(data[id], 1, sizes[id], file); + }); + port->send_n(data, sizes); + port->send([&](rpc::Buffer *buffer, uint32_t id) { + delete[] reinterpret_cast(data[id]); + std::memcpy(buffer->data, &rets[id], sizeof(uint64_t)); + }); + break; + } case RPC_OPEN_FILE: { uint64_t sizes[rpc::MAX_LANE_SIZE] = {0}; void *paths[rpc::MAX_LANE_SIZE] = {nullptr};