1e0b487bfSJoseph Huber //===-- Shared memory RPC server instantiation ------------------*- C++ -*-===// 2e0b487bfSJoseph Huber // 3e0b487bfSJoseph Huber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e0b487bfSJoseph Huber // See https://llvm.org/LICENSE.txt for license information. 5e0b487bfSJoseph Huber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e0b487bfSJoseph Huber // 7e0b487bfSJoseph Huber //===----------------------------------------------------------------------===// 8e0b487bfSJoseph Huber 977118536SMarc Auberer // Workaround for missing __has_builtin in < GCC 10. 1077118536SMarc Auberer #ifndef __has_builtin 1177118536SMarc Auberer #define __has_builtin(x) 0 1277118536SMarc Auberer #endif 1377118536SMarc Auberer 14f126bc98SJoseph Huber // Make sure these are included first so they don't conflict with the system. 15f126bc98SJoseph Huber #include <limits.h> 16f126bc98SJoseph Huber 1789614cebSJoseph Huber #include "shared/rpc.h" 18d7c20a6fSJoseph Huber #include "shared/rpc_opcodes.h" 1989614cebSJoseph Huber 207327014bSJoseph Huber #include "src/__support/arg_list.h" 217327014bSJoseph Huber #include "src/stdio/printf_core/converter.h" 227327014bSJoseph Huber #include "src/stdio/printf_core/parser.h" 237327014bSJoseph Huber #include "src/stdio/printf_core/writer.h" 247327014bSJoseph Huber 257327014bSJoseph Huber #include <algorithm> 26e0b487bfSJoseph Huber #include <atomic> 27e0b487bfSJoseph Huber #include <cstdio> 28e0b487bfSJoseph Huber #include <cstring> 29e0b487bfSJoseph Huber #include <memory> 30e0b487bfSJoseph Huber #include <mutex> 31e0b487bfSJoseph Huber #include <unordered_map> 32e0b487bfSJoseph Huber #include <variant> 33e0b487bfSJoseph Huber #include <vector> 34e0b487bfSJoseph Huber 35b6bc9d72SGuillaume Chatelet using namespace LIBC_NAMESPACE; 367327014bSJoseph Huber using namespace LIBC_NAMESPACE::printf_core; 37e0b487bfSJoseph Huber 38bbe79a80SIvan Butygin namespace { 39bbe79a80SIvan Butygin struct TempStorage { 40bbe79a80SIvan Butygin char *alloc(size_t size) { 41bbe79a80SIvan Butygin storage.emplace_back(std::make_unique<char[]>(size)); 42bbe79a80SIvan Butygin return storage.back().get(); 43bbe79a80SIvan Butygin } 44bbe79a80SIvan Butygin 45bbe79a80SIvan Butygin std::vector<std::unique_ptr<char[]>> storage; 46bbe79a80SIvan Butygin }; 47bbe79a80SIvan Butygin } // namespace 48bbe79a80SIvan Butygin 4989614cebSJoseph Huber enum Stream { 5089614cebSJoseph Huber File = 0, 5189614cebSJoseph Huber Stdin = 1, 5289614cebSJoseph Huber Stdout = 2, 5389614cebSJoseph Huber Stderr = 3, 5489614cebSJoseph Huber }; 5589614cebSJoseph Huber 5689614cebSJoseph Huber // Get the associated stream out of an encoded number. 5789614cebSJoseph Huber LIBC_INLINE ::FILE *to_stream(uintptr_t f) { 5889614cebSJoseph Huber ::FILE *stream = reinterpret_cast<FILE *>(f & ~0x3ull); 5989614cebSJoseph Huber Stream type = static_cast<Stream>(f & 0x3ull); 6089614cebSJoseph Huber if (type == Stdin) 6189614cebSJoseph Huber return stdin; 6289614cebSJoseph Huber if (type == Stdout) 6389614cebSJoseph Huber return stdout; 6489614cebSJoseph Huber if (type == Stderr) 6589614cebSJoseph Huber return stderr; 6689614cebSJoseph Huber return stream; 6789614cebSJoseph Huber } 6889614cebSJoseph Huber 69b4d49fb5SJoseph Huber template <bool packed, uint32_t num_lanes> 70bbe79a80SIvan Butygin static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) { 71b4d49fb5SJoseph Huber FILE *files[num_lanes] = {nullptr}; 727327014bSJoseph Huber // Get the appropriate output stream to use. 73a6ef0debSJoseph Huber if (port.get_opcode() == LIBC_PRINTF_TO_STREAM || 74a6ef0debSJoseph Huber port.get_opcode() == LIBC_PRINTF_TO_STREAM_PACKED) 757327014bSJoseph Huber port.recv([&](rpc::Buffer *buffer, uint32_t id) { 767327014bSJoseph Huber files[id] = reinterpret_cast<FILE *>(buffer->data[0]); 777327014bSJoseph Huber }); 78a6ef0debSJoseph Huber else if (port.get_opcode() == LIBC_PRINTF_TO_STDOUT || 79a6ef0debSJoseph Huber port.get_opcode() == LIBC_PRINTF_TO_STDOUT_PACKED) 80b4d49fb5SJoseph Huber std::fill(files, files + num_lanes, stdout); 817327014bSJoseph Huber else 82b4d49fb5SJoseph Huber std::fill(files, files + num_lanes, stderr); 837327014bSJoseph Huber 84b4d49fb5SJoseph Huber uint64_t format_sizes[num_lanes] = {0}; 85b4d49fb5SJoseph Huber void *format[num_lanes] = {nullptr}; 867327014bSJoseph Huber 87b4d49fb5SJoseph Huber uint64_t args_sizes[num_lanes] = {0}; 88b4d49fb5SJoseph Huber void *args[num_lanes] = {nullptr}; 897327014bSJoseph Huber 907327014bSJoseph Huber // Recieve the format string and arguments from the client. 917327014bSJoseph Huber port.recv_n(format, format_sizes, 92bbe79a80SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 9340effc7aSJoseph Huber 9440effc7aSJoseph Huber // Parse the format string to get the expected size of the buffer. 95b4d49fb5SJoseph Huber for (uint32_t lane = 0; lane < num_lanes; ++lane) { 9640effc7aSJoseph Huber if (!format[lane]) 9740effc7aSJoseph Huber continue; 9840effc7aSJoseph Huber 9940effc7aSJoseph Huber WriteBuffer wb(nullptr, 0); 10040effc7aSJoseph Huber Writer writer(&wb); 10140effc7aSJoseph Huber 10240effc7aSJoseph Huber internal::DummyArgList<packed> printf_args; 10340effc7aSJoseph Huber Parser<internal::DummyArgList<packed> &> parser( 10440effc7aSJoseph Huber reinterpret_cast<const char *>(format[lane]), printf_args); 10540effc7aSJoseph Huber 10640effc7aSJoseph Huber for (FormatSection cur_section = parser.get_next_section(); 10740effc7aSJoseph Huber !cur_section.raw_string.empty(); 10840effc7aSJoseph Huber cur_section = parser.get_next_section()) 10940effc7aSJoseph Huber ; 11040effc7aSJoseph Huber args_sizes[lane] = printf_args.read_count(); 11140effc7aSJoseph Huber } 11240effc7aSJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 11340effc7aSJoseph Huber buffer->data[0] = args_sizes[id]; 11440effc7aSJoseph Huber }); 115bbe79a80SIvan Butygin port.recv_n(args, args_sizes, 116bbe79a80SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 1177327014bSJoseph Huber 1187327014bSJoseph Huber // Identify any arguments that are actually pointers to strings on the client. 1197327014bSJoseph Huber // Additionally we want to determine how much buffer space we need to print. 120b4d49fb5SJoseph Huber std::vector<void *> strs_to_copy[num_lanes]; 121b4d49fb5SJoseph Huber int buffer_size[num_lanes] = {0}; 122b4d49fb5SJoseph Huber for (uint32_t lane = 0; lane < num_lanes; ++lane) { 1237327014bSJoseph Huber if (!format[lane]) 1247327014bSJoseph Huber continue; 1257327014bSJoseph Huber 1267327014bSJoseph Huber WriteBuffer wb(nullptr, 0); 1277327014bSJoseph Huber Writer writer(&wb); 1287327014bSJoseph Huber 12940effc7aSJoseph Huber internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]); 13040effc7aSJoseph Huber Parser<internal::StructArgList<packed>> parser( 1317327014bSJoseph Huber reinterpret_cast<const char *>(format[lane]), printf_args); 1327327014bSJoseph Huber 1337327014bSJoseph Huber for (FormatSection cur_section = parser.get_next_section(); 1347327014bSJoseph Huber !cur_section.raw_string.empty(); 1357327014bSJoseph Huber cur_section = parser.get_next_section()) { 1367327014bSJoseph Huber if (cur_section.has_conv && cur_section.conv_name == 's' && 1377327014bSJoseph Huber cur_section.conv_val_ptr) { 1387327014bSJoseph Huber strs_to_copy[lane].emplace_back(cur_section.conv_val_ptr); 139c8e69fa4SJoseph Huber // Get the minimum size of the string in the case of padding. 140c8e69fa4SJoseph Huber char c = '\0'; 141c8e69fa4SJoseph Huber cur_section.conv_val_ptr = &c; 142c8e69fa4SJoseph Huber convert(&writer, cur_section); 1437327014bSJoseph Huber } else if (cur_section.has_conv) { 1447327014bSJoseph Huber // Ignore conversion errors for the first pass. 1457327014bSJoseph Huber convert(&writer, cur_section); 1467327014bSJoseph Huber } else { 1477327014bSJoseph Huber writer.write(cur_section.raw_string); 1487327014bSJoseph Huber } 1497327014bSJoseph Huber } 1507327014bSJoseph Huber buffer_size[lane] = writer.get_chars_written(); 1517327014bSJoseph Huber } 1527327014bSJoseph Huber 1537327014bSJoseph Huber // Recieve any strings from the client and push them into a buffer. 154b4d49fb5SJoseph Huber std::vector<void *> copied_strs[num_lanes]; 1557327014bSJoseph Huber while (std::any_of(std::begin(strs_to_copy), std::end(strs_to_copy), 1567327014bSJoseph Huber [](const auto &v) { return !v.empty() && v.back(); })) { 1577327014bSJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 1587327014bSJoseph Huber void *ptr = !strs_to_copy[id].empty() ? strs_to_copy[id].back() : nullptr; 1597327014bSJoseph Huber buffer->data[1] = reinterpret_cast<uintptr_t>(ptr); 1607327014bSJoseph Huber if (!strs_to_copy[id].empty()) 1617327014bSJoseph Huber strs_to_copy[id].pop_back(); 1627327014bSJoseph Huber }); 163b4d49fb5SJoseph Huber uint64_t str_sizes[num_lanes] = {0}; 164b4d49fb5SJoseph Huber void *strs[num_lanes] = {nullptr}; 165bbe79a80SIvan Butygin port.recv_n(strs, str_sizes, 166bbe79a80SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 167b4d49fb5SJoseph Huber for (uint32_t lane = 0; lane < num_lanes; ++lane) { 1687327014bSJoseph Huber if (!strs[lane]) 1697327014bSJoseph Huber continue; 1707327014bSJoseph Huber 1717327014bSJoseph Huber copied_strs[lane].emplace_back(strs[lane]); 1727327014bSJoseph Huber buffer_size[lane] += str_sizes[lane]; 1737327014bSJoseph Huber } 1747327014bSJoseph Huber } 1757327014bSJoseph Huber 1767327014bSJoseph Huber // Perform the final formatting and printing using the LLVM C library printf. 177b4d49fb5SJoseph Huber int results[num_lanes] = {0}; 178b4d49fb5SJoseph Huber for (uint32_t lane = 0; lane < num_lanes; ++lane) { 1797327014bSJoseph Huber if (!format[lane]) 1807327014bSJoseph Huber continue; 1817327014bSJoseph Huber 182bbe79a80SIvan Butygin char *buffer = temp_storage.alloc(buffer_size[lane]); 183bbe79a80SIvan Butygin WriteBuffer wb(buffer, buffer_size[lane]); 1847327014bSJoseph Huber Writer writer(&wb); 1857327014bSJoseph Huber 18640effc7aSJoseph Huber internal::StructArgList<packed> printf_args(args[lane], args_sizes[lane]); 18740effc7aSJoseph Huber Parser<internal::StructArgList<packed>> parser( 1887327014bSJoseph Huber reinterpret_cast<const char *>(format[lane]), printf_args); 1897327014bSJoseph Huber 1907327014bSJoseph Huber // Parse and print the format string using the arguments we copied from 1917327014bSJoseph Huber // the client. 1927327014bSJoseph Huber int ret = 0; 1937327014bSJoseph Huber for (FormatSection cur_section = parser.get_next_section(); 1947327014bSJoseph Huber !cur_section.raw_string.empty(); 1957327014bSJoseph Huber cur_section = parser.get_next_section()) { 1967327014bSJoseph Huber // If this argument was a string we use the memory buffer we copied from 1977327014bSJoseph Huber // the client by replacing the raw pointer with the copied one. 1987327014bSJoseph Huber if (cur_section.has_conv && cur_section.conv_name == 's') { 1997327014bSJoseph Huber if (!copied_strs[lane].empty()) { 2007327014bSJoseph Huber cur_section.conv_val_ptr = copied_strs[lane].back(); 2017327014bSJoseph Huber copied_strs[lane].pop_back(); 2027327014bSJoseph Huber } else { 2037327014bSJoseph Huber cur_section.conv_val_ptr = nullptr; 2047327014bSJoseph Huber } 2057327014bSJoseph Huber } 2067327014bSJoseph Huber if (cur_section.has_conv) { 2077327014bSJoseph Huber ret = convert(&writer, cur_section); 2087327014bSJoseph Huber if (ret == -1) 2097327014bSJoseph Huber break; 2107327014bSJoseph Huber } else { 2117327014bSJoseph Huber writer.write(cur_section.raw_string); 2127327014bSJoseph Huber } 2137327014bSJoseph Huber } 2147327014bSJoseph Huber 215bbe79a80SIvan Butygin results[lane] = fwrite(buffer, 1, writer.get_chars_written(), files[lane]); 2167327014bSJoseph Huber if (results[lane] != writer.get_chars_written() || ret == -1) 2177327014bSJoseph Huber results[lane] = -1; 2187327014bSJoseph Huber } 2197327014bSJoseph Huber 2207327014bSJoseph Huber // Send the final return value and signal completion by setting the string 2217327014bSJoseph Huber // argument to null. 2227327014bSJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 2237327014bSJoseph Huber buffer->data[0] = static_cast<uint64_t>(results[id]); 2247327014bSJoseph Huber buffer->data[1] = reinterpret_cast<uintptr_t>(nullptr); 2257327014bSJoseph Huber }); 2267327014bSJoseph Huber } 2277327014bSJoseph Huber 228b4d49fb5SJoseph Huber template <uint32_t num_lanes> 229b4d49fb5SJoseph Huber rpc::Status handle_port_impl(rpc::Server::Port &port) { 230ef390b36SIvan Butygin TempStorage temp_storage; 231ef390b36SIvan Butygin 232b4d49fb5SJoseph Huber switch (port.get_opcode()) { 233a6ef0debSJoseph Huber case LIBC_WRITE_TO_STREAM: 234a6ef0debSJoseph Huber case LIBC_WRITE_TO_STDERR: 235a6ef0debSJoseph Huber case LIBC_WRITE_TO_STDOUT: 236a6ef0debSJoseph Huber case LIBC_WRITE_TO_STDOUT_NEWLINE: { 237b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 238b4d49fb5SJoseph Huber void *strs[num_lanes] = {nullptr}; 239b4d49fb5SJoseph Huber FILE *files[num_lanes] = {nullptr}; 240a6ef0debSJoseph Huber if (port.get_opcode() == LIBC_WRITE_TO_STREAM) { 241b4d49fb5SJoseph Huber port.recv([&](rpc::Buffer *buffer, uint32_t id) { 242e0b487bfSJoseph Huber files[id] = reinterpret_cast<FILE *>(buffer->data[0]); 243e0b487bfSJoseph Huber }); 244a6ef0debSJoseph Huber } else if (port.get_opcode() == LIBC_WRITE_TO_STDERR) { 245b4d49fb5SJoseph Huber std::fill(files, files + num_lanes, stderr); 246791b2799SJoseph Huber } else { 247b4d49fb5SJoseph Huber std::fill(files, files + num_lanes, stdout); 248791b2799SJoseph Huber } 249791b2799SJoseph Huber 250b4d49fb5SJoseph Huber port.recv_n(strs, sizes, 251ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 252b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 253bf02c84cSJoseph Huber flockfile(files[id]); 254bf02c84cSJoseph Huber buffer->data[0] = fwrite_unlocked(strs[id], 1, sizes[id], files[id]); 255a6ef0debSJoseph Huber if (port.get_opcode() == LIBC_WRITE_TO_STDOUT_NEWLINE && 256791b2799SJoseph Huber buffer->data[0] == sizes[id]) 257bf02c84cSJoseph Huber buffer->data[0] += fwrite_unlocked("\n", 1, 1, files[id]); 258bf02c84cSJoseph Huber funlockfile(files[id]); 259e0b487bfSJoseph Huber }); 260e0b487bfSJoseph Huber break; 261e0b487bfSJoseph Huber } 262a6ef0debSJoseph Huber case LIBC_READ_FROM_STREAM: { 263b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 264b4d49fb5SJoseph Huber void *data[num_lanes] = {nullptr}; 265b4d49fb5SJoseph Huber port.recv([&](rpc::Buffer *buffer, uint32_t id) { 266ef390b36SIvan Butygin data[id] = temp_storage.alloc(buffer->data[0]); 26729762e37SJoseph Huber sizes[id] = 26889614cebSJoseph Huber fread(data[id], 1, buffer->data[0], to_stream(buffer->data[1])); 269334bbc0dSJoseph Huber }); 270b4d49fb5SJoseph Huber port.send_n(data, sizes); 271b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 272f548d19fSJoseph Huber std::memcpy(buffer->data, &sizes[id], sizeof(uint64_t)); 273334bbc0dSJoseph Huber }); 274334bbc0dSJoseph Huber break; 275334bbc0dSJoseph Huber } 276a6ef0debSJoseph Huber case LIBC_READ_FGETS: { 277b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 278b4d49fb5SJoseph Huber void *data[num_lanes] = {nullptr}; 279b4d49fb5SJoseph Huber port.recv([&](rpc::Buffer *buffer, uint32_t id) { 280ef390b36SIvan Butygin data[id] = temp_storage.alloc(buffer->data[0]); 28189614cebSJoseph Huber const char *str = fgets(reinterpret_cast<char *>(data[id]), 28289614cebSJoseph Huber buffer->data[0], to_stream(buffer->data[1])); 283a3921576SJoseph Huber sizes[id] = !str ? 0 : std::strlen(str) + 1; 284a3921576SJoseph Huber }); 285b4d49fb5SJoseph Huber port.send_n(data, sizes); 286a3921576SJoseph Huber break; 287a3921576SJoseph Huber } 288a6ef0debSJoseph Huber case LIBC_OPEN_FILE: { 289b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 290b4d49fb5SJoseph Huber void *paths[num_lanes] = {nullptr}; 291b4d49fb5SJoseph Huber port.recv_n(paths, sizes, 292ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 293b4d49fb5SJoseph Huber port.recv_and_send([&](rpc::Buffer *buffer, uint32_t id) { 294c850ea14SJoseph Huber FILE *file = fopen(reinterpret_cast<char *>(paths[id]), 295c850ea14SJoseph Huber reinterpret_cast<char *>(buffer->data)); 296c850ea14SJoseph Huber buffer->data[0] = reinterpret_cast<uintptr_t>(file); 297c850ea14SJoseph Huber }); 298c850ea14SJoseph Huber break; 299c850ea14SJoseph Huber } 300a6ef0debSJoseph Huber case LIBC_CLOSE_FILE: { 301b4d49fb5SJoseph Huber port.recv_and_send([&](rpc::Buffer *buffer, uint32_t id) { 302c850ea14SJoseph Huber FILE *file = reinterpret_cast<FILE *>(buffer->data[0]); 303c850ea14SJoseph Huber buffer->data[0] = fclose(file); 304c850ea14SJoseph Huber }); 305c850ea14SJoseph Huber break; 306c850ea14SJoseph Huber } 307a6ef0debSJoseph Huber case LIBC_EXIT: { 308667c1035SJoseph Huber // Send a response to the client to signal that we are ready to exit. 309b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *, uint32_t) {}); 310b4d49fb5SJoseph Huber port.recv([](rpc::Buffer *buffer, uint32_t) { 311e0b487bfSJoseph Huber int status = 0; 312e0b487bfSJoseph Huber std::memcpy(&status, buffer->data, sizeof(int)); 313e0b487bfSJoseph Huber exit(status); 314e0b487bfSJoseph Huber }); 315e0b487bfSJoseph Huber break; 316e0b487bfSJoseph Huber } 317a6ef0debSJoseph Huber case LIBC_ABORT: { 31807102a11SJoseph Huber // Send a response to the client to signal that we are ready to abort. 319b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *, uint32_t) {}); 320b4d49fb5SJoseph Huber port.recv([](rpc::Buffer *, uint32_t) {}); 32107102a11SJoseph Huber abort(); 32207102a11SJoseph Huber break; 32307102a11SJoseph Huber } 324a6ef0debSJoseph Huber case LIBC_HOST_CALL: { 325b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 326b4d49fb5SJoseph Huber unsigned long long results[num_lanes] = {0}; 327b4d49fb5SJoseph Huber void *args[num_lanes] = {nullptr}; 328b4d49fb5SJoseph Huber port.recv_n(args, sizes, 329ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 330b4d49fb5SJoseph Huber port.recv([&](rpc::Buffer *buffer, uint32_t id) { 33126ca8ef8SIvan Butygin using func_ptr_t = unsigned long long (*)(void *); 33226ca8ef8SIvan Butygin auto func = reinterpret_cast<func_ptr_t>(buffer->data[0]); 33326ca8ef8SIvan Butygin results[id] = func(args[id]); 334e537c839SJoseph Huber }); 335b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 33626ca8ef8SIvan Butygin buffer->data[0] = static_cast<uint64_t>(results[id]); 33726ca8ef8SIvan Butygin }); 338e537c839SJoseph Huber break; 339e537c839SJoseph Huber } 340a6ef0debSJoseph Huber case LIBC_FEOF: { 341b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 34289614cebSJoseph Huber buffer->data[0] = feof(to_stream(buffer->data[0])); 343a1be5d69SJoseph Huber }); 344a1be5d69SJoseph Huber break; 345a1be5d69SJoseph Huber } 346a6ef0debSJoseph Huber case LIBC_FERROR: { 347b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 34889614cebSJoseph Huber buffer->data[0] = ferror(to_stream(buffer->data[0])); 349a1be5d69SJoseph Huber }); 350a1be5d69SJoseph Huber break; 351a1be5d69SJoseph Huber } 352a6ef0debSJoseph Huber case LIBC_CLEARERR: { 353b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 35489614cebSJoseph Huber clearerr(to_stream(buffer->data[0])); 355a1be5d69SJoseph Huber }); 356a1be5d69SJoseph Huber break; 357a1be5d69SJoseph Huber } 358a6ef0debSJoseph Huber case LIBC_FSEEK: { 359b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 36089614cebSJoseph Huber buffer->data[0] = 36189614cebSJoseph Huber fseek(to_stream(buffer->data[0]), static_cast<long>(buffer->data[1]), 3627ac8e26fSJoseph Huber static_cast<int>(buffer->data[2])); 3637ac8e26fSJoseph Huber }); 3647ac8e26fSJoseph Huber break; 3657ac8e26fSJoseph Huber } 366a6ef0debSJoseph Huber case LIBC_FTELL: { 367b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 36889614cebSJoseph Huber buffer->data[0] = ftell(to_stream(buffer->data[0])); 3697ac8e26fSJoseph Huber }); 3707ac8e26fSJoseph Huber break; 3717ac8e26fSJoseph Huber } 372a6ef0debSJoseph Huber case LIBC_FFLUSH: { 373b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 37489614cebSJoseph Huber buffer->data[0] = fflush(to_stream(buffer->data[0])); 3757ac8e26fSJoseph Huber }); 3767ac8e26fSJoseph Huber break; 3777ac8e26fSJoseph Huber } 378a6ef0debSJoseph Huber case LIBC_UNGETC: { 379b4d49fb5SJoseph Huber port.recv_and_send([](rpc::Buffer *buffer, uint32_t) { 38089614cebSJoseph Huber buffer->data[0] = 38189614cebSJoseph Huber ungetc(static_cast<int>(buffer->data[0]), to_stream(buffer->data[1])); 382ddc30ff8SJoseph Huber }); 383ddc30ff8SJoseph Huber break; 384ddc30ff8SJoseph Huber } 385a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STREAM_PACKED: 386a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STDOUT_PACKED: 387a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STDERR_PACKED: { 388b4d49fb5SJoseph Huber handle_printf<true, num_lanes>(port, temp_storage); 38940effc7aSJoseph Huber break; 39040effc7aSJoseph Huber } 391a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STREAM: 392a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STDOUT: 393a6ef0debSJoseph Huber case LIBC_PRINTF_TO_STDERR: { 394b4d49fb5SJoseph Huber handle_printf<false, num_lanes>(port, temp_storage); 3957327014bSJoseph Huber break; 3967327014bSJoseph Huber } 397a6ef0debSJoseph Huber case LIBC_REMOVE: { 398b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 399b4d49fb5SJoseph Huber void *args[num_lanes] = {nullptr}; 400b4d49fb5SJoseph Huber port.recv_n(args, sizes, 401ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 402b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 403ec0e6ef0SJoseph Huber buffer->data[0] = static_cast<uint64_t>( 404ec0e6ef0SJoseph Huber remove(reinterpret_cast<const char *>(args[id]))); 405ec0e6ef0SJoseph Huber }); 406ec0e6ef0SJoseph Huber break; 407ec0e6ef0SJoseph Huber } 408a6ef0debSJoseph Huber case LIBC_RENAME: { 409b4d49fb5SJoseph Huber uint64_t oldsizes[num_lanes] = {0}; 410b4d49fb5SJoseph Huber uint64_t newsizes[num_lanes] = {0}; 411b4d49fb5SJoseph Huber void *oldpath[num_lanes] = {nullptr}; 412b4d49fb5SJoseph Huber void *newpath[num_lanes] = {nullptr}; 413b4d49fb5SJoseph Huber port.recv_n(oldpath, oldsizes, 414ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 415b4d49fb5SJoseph Huber port.recv_n(newpath, newsizes, 416ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 417b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 418fe6a3d46SJoseph Huber buffer->data[0] = static_cast<uint64_t>( 419fe6a3d46SJoseph Huber rename(reinterpret_cast<const char *>(oldpath[id]), 420fe6a3d46SJoseph Huber reinterpret_cast<const char *>(newpath[id]))); 421fe6a3d46SJoseph Huber }); 422fe6a3d46SJoseph Huber break; 423fe6a3d46SJoseph Huber } 424a6ef0debSJoseph Huber case LIBC_SYSTEM: { 425b4d49fb5SJoseph Huber uint64_t sizes[num_lanes] = {0}; 426b4d49fb5SJoseph Huber void *args[num_lanes] = {nullptr}; 427b4d49fb5SJoseph Huber port.recv_n(args, sizes, 428ef390b36SIvan Butygin [&](uint64_t size) { return temp_storage.alloc(size); }); 429b4d49fb5SJoseph Huber port.send([&](rpc::Buffer *buffer, uint32_t id) { 43016d11e26SJoseph Huber buffer->data[0] = static_cast<uint64_t>( 43116d11e26SJoseph Huber system(reinterpret_cast<const char *>(args[id]))); 43216d11e26SJoseph Huber }); 43316d11e26SJoseph Huber break; 43416d11e26SJoseph Huber } 435a6ef0debSJoseph Huber case LIBC_NOOP: { 436b4d49fb5SJoseph Huber port.recv([](rpc::Buffer *, uint32_t) {}); 437e0b487bfSJoseph Huber break; 438e0b487bfSJoseph Huber } 43929762e37SJoseph Huber default: 440*e85a9f55SJinsong Ji return rpc::RPC_UNHANDLED_OPCODE; 44129762e37SJoseph Huber } 44229762e37SJoseph Huber 443*e85a9f55SJinsong Ji return rpc::RPC_SUCCESS; 444e0b487bfSJoseph Huber } 445e0b487bfSJoseph Huber 4461d810eceSJoseph Huber namespace rpc { 4471d810eceSJoseph Huber // The implementation of this function currently lives in the utility directory 4481d810eceSJoseph Huber // at 'utils/gpu/server/rpc_server.cpp'. 4491d810eceSJoseph Huber rpc::Status handle_libc_opcodes(rpc::Server::Port &port, uint32_t num_lanes) { 450b4d49fb5SJoseph Huber switch (num_lanes) { 451b4d49fb5SJoseph Huber case 1: 4521d810eceSJoseph Huber return handle_port_impl<1>(port); 453b4d49fb5SJoseph Huber case 32: 4541d810eceSJoseph Huber return handle_port_impl<32>(port); 455b4d49fb5SJoseph Huber case 64: 4561d810eceSJoseph Huber return handle_port_impl<64>(port); 457b4d49fb5SJoseph Huber default: 458*e85a9f55SJinsong Ji return rpc::RPC_ERROR; 459e0b487bfSJoseph Huber } 460e0b487bfSJoseph Huber } 4611d810eceSJoseph Huber } // namespace rpc 462