Skip to content

Commit e8e267e

Browse files
authored
[libc] Remove use of C++ STL features from rpc_server.cpp (#131169)
Summary: This is done in preparation for making this header only so we can use it without an object library. This will be a transient interface that internal LLVM stuff with use. External people can use it too if they go through the LLVM libc interface for shared stuff but there's no backward compatibility guarantees. Patch just cleans it up prior to the move.
1 parent 3bd71cb commit e8e267e

File tree

1 file changed

+109
-53
lines changed

1 file changed

+109
-53
lines changed

libc/utils/gpu/server/rpc_server.cpp

Lines changed: 109 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,82 @@
1111
#define __has_builtin(x) 0
1212
#endif
1313

14-
// Make sure these are included first so they don't conflict with the system.
15-
#include <limits.h>
16-
1714
#include "shared/rpc.h"
1815
#include "shared/rpc_opcodes.h"
1916

17+
#include "src/__support/CPP/type_traits.h"
2018
#include "src/__support/arg_list.h"
2119
#include "src/stdio/printf_core/converter.h"
2220
#include "src/stdio/printf_core/parser.h"
2321
#include "src/stdio/printf_core/writer.h"
2422

25-
#include <algorithm>
26-
#include <atomic>
27-
#include <cstdio>
28-
#include <cstring>
29-
#include <memory>
30-
#include <mutex>
31-
#include <unordered_map>
32-
#include <variant>
33-
#include <vector>
23+
#include <stdio.h>
24+
#include <stdlib.h>
25+
26+
namespace LIBC_NAMESPACE {
27+
28+
// Minimal replacement for 'std::vector' that works for trivial types.
29+
template <typename T> class TempVector {
30+
static_assert(cpp::is_trivially_constructible<T>::value &&
31+
cpp::is_trivially_destructible<T>::value,
32+
"Not a trivial type.");
33+
T *data;
34+
size_t current;
35+
size_t capacity;
36+
37+
public:
38+
TempVector() : data(nullptr), current(0), capacity(0) {}
39+
40+
~TempVector() { free(data); }
41+
42+
void push_back(const T &value) {
43+
if (current == capacity)
44+
grow();
45+
data[current] = T(value);
46+
++current;
47+
}
48+
49+
void push_back(T &&value) {
50+
if (current == capacity)
51+
grow();
52+
data[current] = T(static_cast<T &&>(value));
53+
++current;
54+
}
55+
56+
void pop_back() { --current; }
3457

35-
using namespace LIBC_NAMESPACE;
36-
using namespace LIBC_NAMESPACE::printf_core;
58+
bool empty() { return current == 0; }
59+
60+
size_t size() { return current; }
61+
62+
T &operator[](size_t index) { return data[index]; }
63+
64+
T &back() { return data[current - 1]; }
65+
66+
private:
67+
void grow() {
68+
size_t new_capacity = capacity ? capacity * 2 : 1;
69+
void *new_data = realloc(data, new_capacity * sizeof(T));
70+
if (!new_data)
71+
abort();
72+
data = static_cast<T *>(new_data);
73+
capacity = new_capacity;
74+
}
75+
};
3776

38-
namespace {
3977
struct TempStorage {
4078
char *alloc(size_t size) {
41-
storage.emplace_back(std::make_unique<char[]>(size));
42-
return storage.back().get();
79+
storage.push_back(reinterpret_cast<char *>(malloc(size)));
80+
return storage.back();
81+
}
82+
83+
~TempStorage() {
84+
for (size_t i = 0; i < storage.size(); ++i)
85+
free(storage[i]);
4386
}
4487

45-
std::vector<std::unique_ptr<char[]>> storage;
88+
TempVector<char *> storage;
4689
};
47-
} // namespace
4890

4991
enum Stream {
5092
File = 0,
@@ -71,15 +113,18 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
71113
FILE *files[num_lanes] = {nullptr};
72114
// Get the appropriate output stream to use.
73115
if (port.get_opcode() == LIBC_PRINTF_TO_STREAM ||
74-
port.get_opcode() == LIBC_PRINTF_TO_STREAM_PACKED)
116+
port.get_opcode() == LIBC_PRINTF_TO_STREAM_PACKED) {
75117
port.recv([&](rpc::Buffer *buffer, uint32_t id) {
76118
files[id] = reinterpret_cast<FILE *>(buffer->data[0]);
77119
});
78-
else if (port.get_opcode() == LIBC_PRINTF_TO_STDOUT ||
79-
port.get_opcode() == LIBC_PRINTF_TO_STDOUT_PACKED)
80-
std::fill(files, files + num_lanes, stdout);
81-
else
82-
std::fill(files, files + num_lanes, stderr);
120+
} else if (port.get_opcode() == LIBC_PRINTF_TO_STDOUT ||
121+
port.get_opcode() == LIBC_PRINTF_TO_STDOUT_PACKED) {
122+
for (uint32_t i = 0; i < num_lanes; ++i)
123+
files[i] = stdout;
124+
} else {
125+
for (uint32_t i = 0; i < num_lanes; ++i)
126+
files[i] = stderr;
127+
}
83128

84129
uint64_t format_sizes[num_lanes] = {0};
85130
void *format[num_lanes] = {nullptr};
@@ -96,14 +141,16 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
96141
if (!format[lane])
97142
continue;
98143

99-
WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
100-
Writer writer(wb);
144+
printf_core::WriteBuffer<
145+
printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
146+
wb(nullptr, 0);
147+
printf_core::Writer writer(wb);
101148

102149
internal::DummyArgList<packed> printf_args;
103-
Parser<internal::DummyArgList<packed> &> parser(
150+
printf_core::Parser<internal::DummyArgList<packed> &> parser(
104151
reinterpret_cast<const char *>(format[lane]), printf_args);
105152

106-
for (FormatSection cur_section = parser.get_next_section();
153+
for (printf_core::FormatSection cur_section = parser.get_next_section();
107154
!cur_section.raw_string.empty();
108155
cur_section = parser.get_next_section())
109156
;
@@ -117,25 +164,27 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
117164

118165
// Identify any arguments that are actually pointers to strings on the client.
119166
// Additionally we want to determine how much buffer space we need to print.
120-
std::vector<void *> strs_to_copy[num_lanes];
167+
TempVector<void *> strs_to_copy[num_lanes];
121168
int buffer_size[num_lanes] = {0};
122169
for (uint32_t lane = 0; lane < num_lanes; ++lane) {
123170
if (!format[lane])
124171
continue;
125172

126-
WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(nullptr, 0);
127-
Writer writer(wb);
173+
printf_core::WriteBuffer<
174+
printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
175+
wb(nullptr, 0);
176+
printf_core::Writer writer(wb);
128177

129178
internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
130-
Parser<internal::StructArgList<packed>> parser(
179+
printf_core::Parser<internal::StructArgList<packed>> parser(
131180
reinterpret_cast<const char *>(format[lane]), printf_args);
132181

133-
for (FormatSection cur_section = parser.get_next_section();
182+
for (printf_core::FormatSection cur_section = parser.get_next_section();
134183
!cur_section.raw_string.empty();
135184
cur_section = parser.get_next_section()) {
136185
if (cur_section.has_conv && cur_section.conv_name == 's' &&
137186
cur_section.conv_val_ptr) {
138-
strs_to_copy[lane].emplace_back(cur_section.conv_val_ptr);
187+
strs_to_copy[lane].push_back(cur_section.conv_val_ptr);
139188
// Get the minimum size of the string in the case of padding.
140189
char c = '\0';
141190
cur_section.conv_val_ptr = &c;
@@ -151,9 +200,14 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
151200
}
152201

153202
// Recieve any strings from the client and push them into a buffer.
154-
std::vector<void *> copied_strs[num_lanes];
155-
while (std::any_of(std::begin(strs_to_copy), std::end(strs_to_copy),
156-
[](const auto &v) { return !v.empty() && v.back(); })) {
203+
TempVector<void *> copied_strs[num_lanes];
204+
auto HasPendingCopies = [](TempVector<void *> v[num_lanes]) {
205+
for (uint32_t i = 0; i < num_lanes; ++i)
206+
if (!v[i].empty() && v[i].back())
207+
return true;
208+
return false;
209+
};
210+
while (HasPendingCopies(strs_to_copy)) {
157211
port.send([&](rpc::Buffer *buffer, uint32_t id) {
158212
void *ptr = !strs_to_copy[id].empty() ? strs_to_copy[id].back() : nullptr;
159213
buffer->data[1] = reinterpret_cast<uintptr_t>(ptr);
@@ -168,7 +222,7 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
168222
if (!strs[lane])
169223
continue;
170224

171-
copied_strs[lane].emplace_back(strs[lane]);
225+
copied_strs[lane].push_back(strs[lane]);
172226
buffer_size[lane] += str_sizes[lane];
173227
}
174228
}
@@ -180,18 +234,19 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
180234
continue;
181235

182236
char *buffer = temp_storage.alloc(buffer_size[lane]);
183-
WriteBuffer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> wb(buffer,
184-
buffer_size[lane]);
185-
Writer writer(wb);
237+
printf_core::WriteBuffer<
238+
printf_core::WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>
239+
wb(buffer, buffer_size[lane]);
240+
printf_core::Writer writer(wb);
186241

187242
internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]);
188-
Parser<internal::StructArgList<packed>> parser(
243+
printf_core::Parser<internal::StructArgList<packed>> parser(
189244
reinterpret_cast<const char *>(format[lane]), printf_args);
190245

191246
// Parse and print the format string using the arguments we copied from
192247
// the client.
193248
int ret = 0;
194-
for (FormatSection cur_section = parser.get_next_section();
249+
for (printf_core::FormatSection cur_section = parser.get_next_section();
195250
!cur_section.raw_string.empty();
196251
cur_section = parser.get_next_section()) {
197252
// If this argument was a string we use the memory buffer we copied from
@@ -242,10 +297,9 @@ rpc::Status handle_port_impl(rpc::Server::Port &port) {
242297
port.recv([&](rpc::Buffer *buffer, uint32_t id) {
243298
files[id] = reinterpret_cast<FILE *>(buffer->data[0]);
244299
});
245-
} else if (port.get_opcode() == LIBC_WRITE_TO_STDERR) {
246-
std::fill(files, files + num_lanes, stderr);
247300
} else {
248-
std::fill(files, files + num_lanes, stdout);
301+
for (uint32_t i = 0; i < num_lanes; ++i)
302+
files[i] = port.get_opcode() == LIBC_WRITE_TO_STDERR ? stderr : stdout;
249303
}
250304

251305
port.recv_n(strs, sizes,
@@ -270,7 +324,7 @@ rpc::Status handle_port_impl(rpc::Server::Port &port) {
270324
});
271325
port.send_n(data, sizes);
272326
port.send([&](rpc::Buffer *buffer, uint32_t id) {
273-
std::memcpy(buffer->data, &sizes[id], sizeof(uint64_t));
327+
__builtin_memcpy(buffer->data, &sizes[id], sizeof(uint64_t));
274328
});
275329
break;
276330
}
@@ -281,7 +335,7 @@ rpc::Status handle_port_impl(rpc::Server::Port &port) {
281335
data[id] = temp_storage.alloc(buffer->data[0]);
282336
const char *str = fgets(reinterpret_cast<char *>(data[id]),
283337
buffer->data[0], to_stream(buffer->data[1]));
284-
sizes[id] = !str ? 0 : std::strlen(str) + 1;
338+
sizes[id] = !str ? 0 : __builtin_strlen(str) + 1;
285339
});
286340
port.send_n(data, sizes);
287341
break;
@@ -310,7 +364,7 @@ rpc::Status handle_port_impl(rpc::Server::Port &port) {
310364
port.recv_and_send([](rpc::Buffer *, uint32_t) {});
311365
port.recv([](rpc::Buffer *buffer, uint32_t) {
312366
int status = 0;
313-
std::memcpy(&status, buffer->data, sizeof(int));
367+
__builtin_memcpy(&status, buffer->data, sizeof(int));
314368
exit(status);
315369
});
316370
break;
@@ -444,17 +498,19 @@ rpc::Status handle_port_impl(rpc::Server::Port &port) {
444498
return rpc::RPC_SUCCESS;
445499
}
446500

501+
} // namespace LIBC_NAMESPACE
502+
447503
namespace rpc {
448504
// The implementation of this function currently lives in the utility directory
449505
// at 'utils/gpu/server/rpc_server.cpp'.
450506
rpc::Status handle_libc_opcodes(rpc::Server::Port &port, uint32_t num_lanes) {
451507
switch (num_lanes) {
452508
case 1:
453-
return handle_port_impl<1>(port);
509+
return LIBC_NAMESPACE::handle_port_impl<1>(port);
454510
case 32:
455-
return handle_port_impl<32>(port);
511+
return LIBC_NAMESPACE::handle_port_impl<32>(port);
456512
case 64:
457-
return handle_port_impl<64>(port);
513+
return LIBC_NAMESPACE::handle_port_impl<64>(port);
458514
default:
459515
return rpc::RPC_ERROR;
460516
}

0 commit comments

Comments
 (0)