163 changes: 163 additions & 0 deletions libc/src/stdio/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,75 @@
add_entrypoint_object(
clearerr
SRCS
clearerr.cpp
HDRS
../clearerr.h
DEPENDS
libc.include.stdio
libc.src.__support.File.file
libc.src.__support.File.platform_file
)

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

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

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

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

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

add_entrypoint_object(
fopen
SRCS
Expand Down Expand Up @@ -140,6 +212,97 @@ add_entrypoint_object(
libc.src.__support.File.platform_file
)

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

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

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

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

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

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

add_entrypoint_object(
fgets
SRCS
fgets.cpp
HDRS
../fgets.h
DEPENDS
libc.src.errno.errno
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.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
113 changes: 113 additions & 0 deletions libc/src/stdio/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,46 @@ add_header_library(
HDRS
file.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.common
.stdin
.stdout
.stderr
)

add_entrypoint_object(
feof
SRCS
feof.cpp
HDRS
../feof.h
DEPENDS
libc.include.stdio
libc.src.__support.RPC.rpc_client
)

add_entrypoint_object(
ferror
SRCS
ferror.cpp
HDRS
../ferror.h
DEPENDS
libc.include.stdio
libc.src.__support.RPC.rpc_client
)

add_entrypoint_object(
clearerr
SRCS
clearerr.cpp
HDRS
../clearerr.h
DEPENDS
libc.include.stdio
libc.src.__support.RPC.rpc_client
)

add_entrypoint_object(
fopen
SRCS
Expand Down Expand Up @@ -105,6 +139,85 @@ add_entrypoint_object(
.gpu_file
)

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

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

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

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

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

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

add_entrypoint_object(
fgets
SRCS
fgets.cpp
HDRS
../fgets.h
DEPENDS
libc.include.stdio
.gpu_file
.feof
.ferror
)

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

#include <stdio.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(void, clearerr, (::FILE * stream)) {
rpc::Client::Port port = rpc::client.open<RPC_FERROR>();
port.send_and_recv(
[=](rpc::Buffer *buffer) { buffer->data[0] = file::from_stream(stream); },
[&](rpc::Buffer *) {});
port.close();
}

} // namespace __llvm_libc
26 changes: 26 additions & 0 deletions libc/src/stdio/gpu/feof.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===-- Implementation of feof --------------------------------------------===//
//
// 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/feof.h"
#include "file.h"

#include <stdio.h>

namespace __llvm_libc {

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

} // namespace __llvm_libc
26 changes: 26 additions & 0 deletions libc/src/stdio/gpu/ferror.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===-- Implementation of ferror ------------------------------------------===//
//
// 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/ferror.h"
#include "file.h"

#include <stdio.h>

namespace __llvm_libc {

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

} // namespace __llvm_libc
25 changes: 25 additions & 0 deletions libc/src/stdio/gpu/fgetc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- GPU implementation of fgetc ---------------------------------------===//
//
// 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/fgetc.h"
#include "file.h"

#include <stdio.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, fgetc, (::FILE * stream)) {
unsigned char c;
size_t r = file::read(stream, &c, 1);

if (r != 1)
return EOF;
return c;
}

} // namespace __llvm_libc
46 changes: 46 additions & 0 deletions libc/src/stdio/gpu/fgets.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- GPU implementation of fgets ---------------------------------------===//
//
// 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/fgets.h"
#include "file.h"
#include "src/stdio/feof.h"
#include "src/stdio/ferror.h"

#include <stddef.h>
#include <stdio.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(char *, fgets,
(char *__restrict str, int count,
::FILE *__restrict stream)) {
if (count < 1)
return nullptr;

// This implementation is very slow as it makes multiple RPC calls.
unsigned char c = '\0';
int i = 0;
for (; i < count - 1 && c != '\n'; ++i) {
auto r = file::read(stream, &c, 1);
if (r != 1)
break;

str[i] = c;
}

bool has_error = __llvm_libc::ferror(stream);
bool has_eof = __llvm_libc::feof(stream);

if (has_error || (i == 0 && has_eof))
return nullptr;

str[i] = '\0';
return str;
}

} // namespace __llvm_libc
33 changes: 33 additions & 0 deletions libc/src/stdio/gpu/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,38 @@ LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) {
return read_from_stream<RPC_READ_FROM_STREAM>(f, data, size);
}

enum Stream {
File = 0,
Stdin = 1,
Stdout = 2,
Stderr = 3,
};

// When copying between the client and server we need to indicate if this is one
// of the special streams. We do this by enocding the low order bits of the
// pointer to indicate if we need to use the host's standard stream.
LIBC_INLINE uintptr_t from_stream(::FILE *f) {
if (f == stdin)
return reinterpret_cast<uintptr_t>(f) | Stdin;
if (f == stdout)
return reinterpret_cast<uintptr_t>(f) | Stdout;
if (f == stderr)
return reinterpret_cast<uintptr_t>(f) | Stderr;
return reinterpret_cast<uintptr_t>(f);
}

// Get the associated stream out of an encoded number.
LIBC_INLINE ::FILE *to_stream(uintptr_t f) {
::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull);
Stream type = static_cast<Stream>(f & 0x3ull);
if (type == Stdin)
return stdin;
if (type == Stdout)
return stdout;
if (type == Stderr)
return stderr;
return stream;
}

} // namespace file
} // namespace __llvm_libc
25 changes: 25 additions & 0 deletions libc/src/stdio/gpu/getc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- GPU implementation of getc ----------------------------------------===//
//
// 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/getc.h"
#include "file.h"

#include <stdio.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, getc, (::FILE * stream)) {
unsigned char c;
size_t r = file::read(stream, &c, 1);

if (r != 1)
return EOF;
return c;
}

} // namespace __llvm_libc
25 changes: 25 additions & 0 deletions libc/src/stdio/gpu/getchar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===-- GPU implementation of getchar -------------------------------------===//
//
// 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/getchar.h"
#include "file.h"

#include <stdio.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, getchar, ()) {
unsigned char c;
size_t r = file::read(stdin, &c, 1);

if (r != 1)
return EOF;
return c;
}

} // namespace __llvm_libc
6 changes: 3 additions & 3 deletions libc/test/src/stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ add_libc_test(
libc.src.stdio.fopen
)

add_libc_unittest(
add_libc_test(
putc_test
SUITE
libc_stdio_unittests
Expand Down Expand Up @@ -330,7 +330,7 @@ if(${LIBC_TARGET_OS} STREQUAL "linux")
)
endif()

add_libc_unittest(
add_libc_test(
fgetc_test
SUITE
libc_stdio_unittests
Expand Down Expand Up @@ -370,7 +370,7 @@ add_libc_unittest(
libc.src.stdio.getc_unlocked
)

add_libc_unittest(
add_libc_test(
fgets_test
SUITE
libc_stdio_unittests
Expand Down
19 changes: 19 additions & 0 deletions libc/utils/gpu/server/rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "rpc_server.h"

#include "src/__support/RPC/rpc.h"
#include "src/stdio/gpu/file.h"
#include <atomic>
#include <cstdio>
#include <cstring>
Expand Down Expand Up @@ -164,6 +165,24 @@ struct Server {
});
break;
}
case RPC_FEOF: {
port->recv_and_send([](rpc::Buffer *buffer) {
buffer->data[0] = feof(file::to_stream(buffer->data[0]));
});
break;
}
case RPC_FERROR: {
port->recv_and_send([](rpc::Buffer *buffer) {
buffer->data[0] = ferror(file::to_stream(buffer->data[0]));
});
break;
}
case RPC_CLEARERR: {
port->recv_and_send([](rpc::Buffer *buffer) {
clearerr(file::to_stream(buffer->data[0]));
});
break;
}
case RPC_NOOP: {
port->recv([](rpc::Buffer *) {});
break;
Expand Down