runtime/lib/src/pipe.cpp
2025-02-14 23:10:29 -05:00

72 lines
1.9 KiB
C++

#include <utility>
#include <variant>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include "lib.h"
// Load Pipes
static std::variant<int, Trampoline::Error> get_pipe(const char *env) {
const char *value = getenv(env);
if (value == nullptr) {
return Trampoline::Error::MISSING_PIPE;
}
try {
const int val = std::stoi(value);
if (val >= 0) {
return val;
}
} catch (...) {
}
return Trampoline::Error::INVALID_PIPE;
}
#define set(var, env) \
val = get_pipe(env); \
if (std::holds_alternative<Error>(val)) { \
status = std::get<Error>(val); \
return; \
} \
var = std::get<int>(val)
PipeTrampoline::PipeTrampoline() {
std::variant<int, Error> val;
set(arguments_pipe, _MCPI_TRAMPOLINE_ARGUMENTS_ENV);
set(return_value_pipe, _MCPI_TRAMPOLINE_RETURN_VALUE_ENV);
// Success
status = Error::NONE;
}
#undef set
// Call
Trampoline::Error PipeTrampoline::call(const uint32_t id, uint32_t *ret_ptr, const uint32_t length, const unsigned char *args) {
// Check
if (status != Error::NONE) {
return status;
}
// Write Command
const trampoline_pipe_arguments cmd = {
.id = id,
.allow_early_return = ret_ptr == nullptr,
.length = length
};
if (write(arguments_pipe, &cmd, sizeof(trampoline_pipe_arguments)) != sizeof(trampoline_pipe_arguments)) {
return Error::PIPE_WRITE;
}
// Write Arguments
size_t position = 0;
while (position < length) {
const ssize_t ret = write(arguments_pipe, args + position, length - position);
if (ret == -1) {
return Error::PIPE_WRITE;
} else {
position += ret;
}
}
// Return Value
if (ret_ptr != nullptr && read(return_value_pipe, ret_ptr, sizeof(uint32_t)) != sizeof(uint32_t)) {
return Error::PIPE_READ;
}
// Success
return Error::NONE;
}