Skip to content

[libc] Implement the 'ungetc' function on the GPU #69248

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/gpu/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.fgetc
libc.src.stdio.getc
libc.src.stdio.getchar
libc.src.stdio.ungetc
libc.src.stdio.stdin
libc.src.stdio.stdout
libc.src.stdio.stderr
Expand Down
1 change: 1 addition & 0 deletions libc/docs/gpu/support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ ftell |check| |check|
fflush |check| |check|
fgetc |check| |check|
fgets |check| |check|
ungetc |check| |check|
getc |check| |check|
getchar |check| |check|
puts |check| |check|
Expand Down
1 change: 1 addition & 0 deletions libc/include/llvm-libc-types/rpc_opcodes_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ typedef enum {
RPC_FSEEK,
RPC_FTELL,
RPC_FFLUSH,
RPC_UNGETC,
RPC_LAST = 0xFFFF,
} rpc_opcode_t;

Expand Down
13 changes: 1 addition & 12 deletions libc/src/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,6 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)

add_entrypoint_object(
ungetc
SRCS
ungetc.cpp
HDRS
ungetc.h
DEPENDS
libc.include.stdio
libc.src.__support.File.file
libc.src.__support.File.platform_file
)

add_entrypoint_object(
fopencookie
SRCS
Expand Down Expand Up @@ -286,6 +274,7 @@ add_stdio_entrypoint_object(getc_unlocked)
add_stdio_entrypoint_object(getchar)
add_stdio_entrypoint_object(getchar_unlocked)
add_stdio_entrypoint_object(fgets)
add_stdio_entrypoint_object(ungetc)
add_stdio_entrypoint_object(stdin)
add_stdio_entrypoint_object(stdout)
add_stdio_entrypoint_object(stderr)
12 changes: 12 additions & 0 deletions libc/src/stdio/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,18 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)

add_entrypoint_object(
ungetc
SRCS
ungetc.cpp
HDRS
../ungetc.h
DEPENDS
libc.include.stdio
libc.src.__support.File.file
libc.src.__support.File.platform_file
)

add_entrypoint_object(
stdin
SRCS
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions libc/src/stdio/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,17 @@ add_entrypoint_object(
.ferror
)

add_entrypoint_object(
ungetc
SRCS
ungetc.cpp
HDRS
../ungetc.h
DEPENDS
libc.include.stdio
.gpu_file
)

add_entrypoint_object(
stdin
SRCS
Expand Down
29 changes: 29 additions & 0 deletions libc/src/stdio/gpu/ungetc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===-- Implementation of ungetc ------------------------------------------===//
//
// 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/stdio/ungetc.h"
#include "file.h"

#include <stdio.h>

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(int, ungetc, (int c, ::FILE *stream)) {
int ret;
rpc::Client::Port port = rpc::client.open<RPC_UNGETC>();
port.send_and_recv(
[=](rpc::Buffer *buffer) {
buffer->data[0] = c;
buffer->data[1] = file::from_stream(stream);
},
[&](rpc::Buffer *buffer) { ret = static_cast<int>(buffer->data[0]); });
port.close();
return ret;
}

} // namespace LIBC_NAMESPACE
8 changes: 8 additions & 0 deletions libc/test/src/stdio/ungetc_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
constexpr size_t CONTENT_SIZE = sizeof(CONTENT);
ASSERT_EQ(CONTENT_SIZE,
LIBC_NAMESPACE::fwrite(CONTENT, 1, CONTENT_SIZE, file));
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
// Cannot unget to an un-readable file.
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
#endif
ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));

file = LIBC_NAMESPACE::fopen(FILENAME, "r+");
ASSERT_FALSE(file == nullptr);
// Calling with an EOF should always return EOF without doing anything.
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(EOF, file));
char c;
ASSERT_EQ(LIBC_NAMESPACE::fread(&c, 1, 1, file), size_t(1));
ASSERT_EQ(c, CONTENT[0]);
Expand All @@ -43,8 +47,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
// ungetc should not fail after a seek operation.
int unget_char = 'z';
ASSERT_EQ(unget_char, LIBC_NAMESPACE::ungetc(unget_char, file));
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
// Another unget should fail.
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc(unget_char, file));
#endif
// ungetting a char at the beginning of the file will allow us to fetch
// one additional character.
char new_data[CONTENT_SIZE + 1];
Expand All @@ -53,8 +59,10 @@ TEST(LlvmLibcUngetcTest, UngetAndReadBack) {
ASSERT_STREQ("zabcdef", new_data);

ASSERT_EQ(size_t(1), LIBC_NAMESPACE::fwrite("x", 1, 1, file));
#ifndef LIBC_TARGET_ARCH_IS_GPU // Behavior varies between libc implementations.
// unget should fail after a write operation.
ASSERT_EQ(EOF, LIBC_NAMESPACE::ungetc('1', file));
#endif

ASSERT_EQ(0, LIBC_NAMESPACE::fclose(file));
}
7 changes: 7 additions & 0 deletions libc/utils/gpu/server/rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ struct Server {
});
break;
}
case RPC_UNGETC: {
port->recv_and_send([](rpc::Buffer *buffer) {
buffer->data[0] = ungetc(static_cast<int>(buffer->data[0]),
file::to_stream(buffer->data[1]));
});
break;
}
case RPC_NOOP: {
port->recv([](rpc::Buffer *) {});
break;
Expand Down