Skip to content

Commit a392157

Browse files
authored
[libc] Rework the 'fgets' implementation on the GPU (#69635)
Summary: The `fgets` function as implemented is not functional currently when called with multiple threads. This is because we rely on reapeatedly polling the character to detect EOF. This doesn't work when there are multiple threads that may with to poll the characters. this patch pulls out the logic into a standalone RPC call to handle this in a single operation such that calling it from multiple threads functions as expected. It also makes it less slow because we no longer make N RPC calls for N characters.
1 parent 049993e commit a392157

File tree

3 files changed

+29
-16
lines changed

3 files changed

+29
-16
lines changed

libc/include/llvm-libc-types/rpc_opcodes_t.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ typedef enum {
1717
RPC_WRITE_TO_STREAM,
1818
RPC_WRITE_TO_STDOUT_NEWLINE,
1919
RPC_READ_FROM_STREAM,
20+
RPC_READ_FGETS,
2021
RPC_OPEN_FILE,
2122
RPC_CLOSE_FILE,
2223
RPC_MALLOC,

libc/src/stdio/gpu/fgets.cpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,20 @@ LLVM_LIBC_FUNCTION(char *, fgets,
2222
if (count < 1)
2323
return nullptr;
2424

25-
// This implementation is very slow as it makes multiple RPC calls.
26-
unsigned char c = '\0';
27-
int i = 0;
28-
for (; i < count - 1 && c != '\n'; ++i) {
29-
auto r = file::read(stream, &c, 1);
30-
if (r != 1)
31-
break;
32-
33-
str[i] = c;
34-
}
35-
36-
bool has_error = LIBC_NAMESPACE::ferror(stream);
37-
bool has_eof = LIBC_NAMESPACE::feof(stream);
38-
39-
if (has_error || (i == 0 && has_eof))
25+
uint64_t recv_size;
26+
void *buf = nullptr;
27+
rpc::Client::Port port = rpc::client.open<RPC_READ_FGETS>();
28+
port.send([=](rpc::Buffer *buffer) {
29+
buffer->data[0] = count;
30+
buffer->data[1] = file::from_stream(stream);
31+
});
32+
port.recv_n(&buf, &recv_size,
33+
[&](uint64_t) { return reinterpret_cast<void *>(str); });
34+
port.close();
35+
36+
if (recv_size == 0)
4037
return nullptr;
4138

42-
str[i] = '\0';
4339
return str;
4440
}
4541

libc/utils/gpu/server/rpc_server.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,22 @@ struct Server {
101101
});
102102
break;
103103
}
104+
case RPC_READ_FGETS: {
105+
uint64_t sizes[lane_size] = {0};
106+
void *data[lane_size] = {nullptr};
107+
port->recv([&](rpc::Buffer *buffer, uint32_t id) {
108+
data[id] = new char[buffer->data[0]];
109+
const char *str =
110+
fgets(reinterpret_cast<char *>(data[id]), buffer->data[0],
111+
file::to_stream(buffer->data[1]));
112+
sizes[id] = !str ? 0 : std::strlen(str) + 1;
113+
});
114+
port->send_n(data, sizes);
115+
for (uint32_t id = 0; id < lane_size; ++id)
116+
if (data[id])
117+
delete[] reinterpret_cast<uint8_t *>(data[id]);
118+
break;
119+
}
104120
case RPC_OPEN_FILE: {
105121
uint64_t sizes[lane_size] = {0};
106122
void *paths[lane_size] = {nullptr};

0 commit comments

Comments
 (0)