move orbis-kernel to kernel/orbis

This commit is contained in:
DH 2025-10-04 15:07:41 +03:00
parent 7419457efd
commit ecaf607a8f
120 changed files with 1 additions and 1 deletions

View file

@ -0,0 +1,420 @@
#include "orbis/KernelContext.hpp"
#include "orbis/thread/Process.hpp"
#include "orbis/thread/ProcessOps.hpp"
#include "orbis/utils/Logs.hpp"
#include "utils/SharedAtomic.hpp"
#include <bit>
#include <chrono>
#include <csignal>
#include <cstdio>
#include <mutex>
#include <sys/mman.h>
#include <thread>
#include <unistd.h>
#include <utility>
static const std::uint64_t g_allocProtWord = 0xDEADBEAFBADCAFE1;
static constexpr std::uintptr_t kHeapBaseAddress = 0x00000600'0000'0000;
static constexpr auto kHeapSize = 0x1'0000'0000;
static constexpr int kDebugHeap = 0;
namespace orbis {
thread_local Thread *g_currentThread;
KernelContext &g_context = *[]() -> KernelContext * {
// Allocate global shared kernel memory
// TODO: randomize for hardening and reduce size
auto ptr = mmap(std::bit_cast<void *>(kHeapBaseAddress), kHeapSize,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (ptr == MAP_FAILED) {
perror("mmap failed");
FILE *maps = fopen("/proc/self/maps", "r");
char *line = nullptr;
std::size_t size = 0;
while (getline(&line, &size, maps) > 0) {
std::printf("%s", line);
}
free(line);
fclose(maps);
std::abort();
}
return new (ptr) KernelContext;
}();
KernelContext::KernelContext() {
// std::printf("orbis::KernelContext initialized, addr=%p\n", this);
// std::printf("TSC frequency: %lu\n", getTscFreq());
}
KernelContext::~KernelContext() {}
Process *KernelContext::createProcess(pid_t pid) {
auto newProcess = knew<utils::LinkedNode<Process>>();
newProcess->object.context = this;
newProcess->object.pid = pid;
newProcess->object.state = ProcessState::NEW;
{
std::lock_guard lock(m_proc_mtx);
if (m_processes != nullptr) {
m_processes->insertPrev(*newProcess);
}
m_processes = newProcess;
}
return &newProcess->object;
}
void KernelContext::deleteProcess(Process *proc) {
auto procNode = reinterpret_cast<utils::LinkedNode<Process> *>(proc);
{
std::lock_guard lock(m_proc_mtx);
auto next = procNode->erase();
if (procNode == m_processes) {
m_processes = next;
}
}
kdelete(procNode);
}
Process *KernelContext::findProcessById(pid_t pid) const {
for (std::size_t i = 0; i < 20; ++i) {
{
std::lock_guard lock(m_proc_mtx);
for (auto proc = m_processes; proc != nullptr; proc = proc->next) {
if (proc->object.pid == pid) {
return &proc->object;
}
}
}
std::this_thread::sleep_for(std::chrono::microseconds(50));
}
return nullptr;
}
Process *KernelContext::findProcessByHostId(std::uint64_t pid) const {
for (std::size_t i = 0; i < 20; ++i) {
{
std::lock_guard lock(m_proc_mtx);
for (auto proc = m_processes; proc != nullptr; proc = proc->next) {
if (proc->object.hostPid == pid) {
return &proc->object;
}
}
}
std::this_thread::sleep_for(std::chrono::microseconds(50));
}
return nullptr;
}
long KernelContext::getTscFreq() {
auto cal_tsc = []() -> long {
const long timer_freq = 1'000'000'000;
// Calibrate TSC
constexpr int samples = 40;
long rdtsc_data[samples];
long timer_data[samples];
long error_data[samples];
struct ::timespec ts0;
clock_gettime(CLOCK_MONOTONIC, &ts0);
long sec_base = ts0.tv_sec;
for (int i = 0; i < samples; i++) {
usleep(200);
error_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc());
struct ::timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
rdtsc_data[i] = (__builtin_ia32_lfence(), __builtin_ia32_rdtsc());
timer_data[i] = ts.tv_nsec + (ts.tv_sec - sec_base) * 1'000'000'000;
}
// Compute average TSC
long acc = 0;
for (int i = 0; i < samples - 1; i++) {
acc += (rdtsc_data[i + 1] - rdtsc_data[i]) * timer_freq /
(timer_data[i + 1] - timer_data[i]);
}
// Rounding
acc /= (samples - 1);
constexpr long grain = 1'000'000;
return grain * (acc / grain + long{(acc % grain) > (grain / 2)});
};
long freq = m_tsc_freq.load();
if (freq)
return freq;
m_tsc_freq.compare_exchange_strong(freq, cal_tsc());
return m_tsc_freq.load();
}
void *KernelContext::kalloc(std::size_t size, std::size_t align) {
size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) &
~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);
if (!size)
std::abort();
if (m_heap_map_mtx.try_lock()) {
std::lock_guard lock(m_heap_map_mtx, std::adopt_lock);
// Try to reuse previously freed block
for (auto [it, end] = m_free_heap.equal_range(size); it != end; ++it) {
auto result = it->second;
if (!(std::bit_cast<std::uintptr_t>(result) & (align - 1))) {
auto node = m_free_heap.extract(it);
node.key() = 0;
node.mapped() = nullptr;
m_used_node.insert(m_used_node.begin(), std::move(node));
// std::fprintf(stderr, "kalloc: reuse %p-%p, size = %lx\n", result,
// (char *)result + size, size);
if (kDebugHeap > 0) {
std::memcpy(std::bit_cast<std::byte *>(result) + size,
&g_allocProtWord, sizeof(g_allocProtWord));
}
return result;
}
}
}
std::lock_guard lock(m_heap_mtx);
align = std::max<std::size_t>(align, __STDCPP_DEFAULT_NEW_ALIGNMENT__);
auto heap = reinterpret_cast<std::uintptr_t>(m_heap_next);
heap = (heap + (align - 1)) & ~(align - 1);
if (kDebugHeap > 1) {
if (auto diff = (heap + size + sizeof(g_allocProtWord)) % 4096; diff != 0) {
heap += 4096 - diff;
heap &= ~(align - 1);
}
}
if (heap + size > kHeapBaseAddress + kHeapSize) {
std::fprintf(stderr, "out of kernel memory");
std::abort();
}
// Check overflow
if (heap + size < heap) {
std::fprintf(stderr, "too big allocation");
std::abort();
}
// std::fprintf(stderr, "kalloc: allocate %lx-%lx, size = %lx, align=%lx\n",
// heap, heap + size, size, align);
auto result = reinterpret_cast<void *>(heap);
if (kDebugHeap > 0) {
std::memcpy(std::bit_cast<std::byte *>(result) + size, &g_allocProtWord,
sizeof(g_allocProtWord));
}
if (kDebugHeap > 0) {
m_heap_next =
reinterpret_cast<void *>(heap + size + sizeof(g_allocProtWord));
} else {
m_heap_next = reinterpret_cast<void *>(heap + size);
}
if (kDebugHeap > 1) {
heap = reinterpret_cast<std::uintptr_t>(m_heap_next);
align = std::min<std::size_t>(align, 4096);
heap = (heap + (align - 1)) & ~(align - 1);
size = 4096;
// std::fprintf(stderr, "kalloc: protect %lx-%lx, size = %lx, align=%lx\n",
// heap, heap + size, size, align);
auto result = ::mmap(reinterpret_cast<void *>(heap), size, PROT_NONE,
MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (result == MAP_FAILED) {
std::fprintf(stderr, "failed to protect memory");
std::abort();
}
m_heap_next = reinterpret_cast<void *>(heap + size);
}
return result;
}
void KernelContext::kfree(void *ptr, std::size_t size) {
size = (size + (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1)) &
~(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);
if (!size)
std::abort();
if (std::bit_cast<std::uintptr_t>(ptr) < kHeapBaseAddress ||
std::bit_cast<std::uintptr_t>(ptr) + size >
kHeapBaseAddress + kHeapSize) {
std::fprintf(stderr, "kfree: invalid address");
std::abort();
}
if (kDebugHeap > 0) {
if (std::memcmp(std::bit_cast<std::byte *>(ptr) + size, &g_allocProtWord,
sizeof(g_allocProtWord)) != 0) {
std::fprintf(stderr, "kernel heap corruption\n");
std::abort();
}
std::memset(ptr, 0xcc, size + sizeof(g_allocProtWord));
}
// std::fprintf(stderr, "kfree: release %p-%p, size = %lx\n", ptr,
// (char *)ptr + size, size);
std::lock_guard lock(m_heap_map_mtx);
if (!m_used_node.empty()) {
auto node = m_used_node.extract(m_used_node.begin());
node.key() = size;
node.mapped() = ptr;
m_free_heap.insert(std::move(node));
} else {
m_free_heap.emplace(size, ptr);
}
}
std::tuple<UmtxChain &, UmtxKey, std::unique_lock<shared_mutex>>
KernelContext::getUmtxChainIndexed(int i, Thread *t, uint32_t flags,
void *ptr) {
auto pid = t->tproc->pid;
auto p = reinterpret_cast<std::uintptr_t>(ptr);
if (flags & 1) {
pid = 0; // Process shared (TODO)
ORBIS_LOG_WARNING("Using process-shared umtx", t->tid, ptr, (p % 0x4000));
t->where();
}
auto n = p + pid;
if (flags & 1)
n %= 0x4000;
n = ((n * c_golden_ratio_prime) >> c_umtx_shifts) % c_umtx_chains;
std::unique_lock lock(m_umtx_chains[i][n].mtx);
return {m_umtx_chains[i][n], UmtxKey{p, pid}, std::move(lock)};
}
inline namespace utils {
void kfree(void *ptr, std::size_t size) { return g_context.kfree(ptr, size); }
void *kalloc(std::size_t size, std::size_t align) {
return g_context.kalloc(size, align);
}
} // namespace utils
inline namespace logs {
template <>
void log_class_string<kstring>::format(std::string &out, const void *arg) {
out += get_object(arg);
}
} // namespace logs
void Thread::suspend() { sendSignal(-1); }
void Thread::resume() { sendSignal(-2); }
void Thread::sendSignal(int signo) {
if (signo >= 0) {
if (!sigMask.test(signo)) {
return;
}
}
// TODO: suspend uses another delivery confirmation
if (signo != -1) {
interruptedMtx.store(1, std::memory_order::release);
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) {
perror("pthread_sigqueue");
}
while (interruptedMtx.wait(1, std::chrono::microseconds(1000)) !=
std::errc{}) {
if (interruptedMtx.load() == 0) {
return;
}
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = -2})) {
perror("pthread_sigqueue");
}
}
} else {
if (pthread_sigqueue(getNativeHandle(), SIGUSR1, {.sival_int = signo})) {
perror("pthread_sigqueue");
}
}
}
void Thread::notifyUnblockedSignal(int signo) {
for (std::size_t i = 0; i < blockedSignals.size();) {
if (blockedSignals[i].signo != signo) {
++i;
continue;
}
queuedSignals.push_back(blockedSignals[i]);
blockedSignals.erase(blockedSignals.begin() + i);
}
}
void Thread::setSigMask(SigSet newSigMask) {
newSigMask.clear(kSigKill);
newSigMask.clear(kSigStop);
auto oldSigMask = std::exchange(sigMask, newSigMask);
for (std::size_t word = 0; word < std::size(newSigMask.bits); ++word) {
auto unblockedBits = ~oldSigMask.bits[word] & newSigMask.bits[word];
std::uint32_t offset = word * 32 + 1;
for (std::uint32_t i = std::countr_zero(unblockedBits); i < 32;
i += std::countr_zero(unblockedBits >> (i + 1)) + 1) {
notifyUnblockedSignal(offset + i);
}
}
}
void Thread::where() { tproc->ops->where(this); }
bool Thread::unblock() {
std::uint32_t prev = interruptedMtx.exchange(0, std::memory_order::relaxed);
if (prev != 0) {
interruptedMtx.notify_one();
return false;
}
tproc->ops->unblock(this);
return true;
}
bool Thread::block() {
tproc->ops->block(this);
std::uint32_t prev = interruptedMtx.exchange(0, std::memory_order::relaxed);
if (prev != 0) {
interruptedMtx.notify_one();
}
return prev == 0;
}
scoped_unblock::scoped_unblock() {
if (g_currentThread && g_currentThread->context) {
g_scopedUnblock = [](bool unblock) {
if (unblock) {
return g_currentThread->unblock();
}
return g_currentThread->block();
};
}
}
scoped_unblock::~scoped_unblock() { g_scopedUnblock = nullptr; }
} // namespace orbis

103
kernel/orbis/src/event.cpp Normal file
View file

@ -0,0 +1,103 @@
#include "event.hpp"
#include "thread/Process.hpp"
#include <algorithm>
orbis::KNote::~KNote() {
while (!emitters.empty()) {
emitters.back()->unsubscribe(this);
}
if (linked == nullptr) {
return;
}
if (event.filter == kEvFiltProc) {
auto proc = static_cast<Process *>(linked);
std::lock_guard lock(proc->event.mutex);
proc->event.notes.erase(this);
}
}
void orbis::EventEmitter::emit(sshort filter, uint fflags, intptr_t data,
uintptr_t ident) {
std::lock_guard lock(mutex);
for (auto note : notes) {
if (note->event.filter != filter) {
continue;
}
if (fflags != 0) {
if ((note->event.fflags & fflags) == 0) {
continue;
}
note->event.fflags = fflags;
}
if (ident != std::numeric_limits<uintptr_t>::max() &&
note->event.ident != ident) {
continue;
}
std::lock_guard lock(note->mutex);
if (note->triggered) {
continue;
}
note->triggered = true;
note->event.data = data;
note->queue->cv.notify_all(note->queue->mtx);
}
}
void orbis::EventEmitter::emit(
sshort filter, void *userData,
std::optional<intptr_t> (*filterFn)(void *userData, KNote *note)) {
std::lock_guard lock(mutex);
for (auto note : notes) {
if (note->event.filter != filter) {
continue;
}
std::lock_guard lock(note->mutex);
if (note->triggered) {
continue;
}
if (auto data = filterFn(userData, note)) {
note->event.data = *data;
note->triggered = true;
note->queue->cv.notify_all(note->queue->mtx);
}
}
}
void orbis::EventEmitter::subscribe(KNote *note) {
std::lock_guard lock(mutex);
notes.insert(note);
note->emitters.emplace_back(this);
}
void orbis::EventEmitter::unsubscribe(KNote *note) {
std::lock_guard lock(mutex);
notes.erase(note);
auto it = std::ranges::find(note->emitters, this);
if (it == note->emitters.end()) {
return;
}
std::size_t index = it - note->emitters.begin();
auto lastEmitter = note->emitters.size() - 1;
if (index != lastEmitter) {
std::swap(note->emitters[index], note->emitters[lastEmitter]);
}
note->emitters.pop_back();
}

157
kernel/orbis/src/evf.cpp Normal file
View file

@ -0,0 +1,157 @@
#include "evf.hpp"
#include "error/ErrorCode.hpp"
#include "utils/Logs.hpp"
#include "utils/SharedCV.hpp"
#include <atomic>
orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode,
std::uint64_t bitPattern,
std::uint32_t *timeout) {
using namespace std::chrono;
steady_clock::time_point start{};
uint64_t elapsed = 0;
uint64_t fullTimeout = -1;
if (timeout) {
start = steady_clock::now();
fullTimeout = *timeout;
}
auto update_timeout = [&] {
if (!timeout)
return;
auto now = steady_clock::now();
elapsed = duration_cast<microseconds>(now - start).count();
if (fullTimeout > elapsed) {
*timeout = fullTimeout - elapsed;
return;
}
*timeout = 0;
};
thread->evfResultPattern = 0;
thread->evfIsCancelled = -1;
std::unique_lock lock(queueMtx);
orbis::ErrorCode result = {};
while (true) {
if (isDeleted) {
if (thread->evfIsCancelled == UINT64_MAX)
thread->evfResultPattern = value.load();
return ErrorCode::ACCES;
}
if (thread->evfIsCancelled == 1) {
return ErrorCode::CANCELED;
}
if (thread->evfIsCancelled == 0) {
break;
}
thread->evfResultPattern = 0;
thread->evfIsCancelled = -1;
auto waitingThread = WaitingThread{
.thread = thread, .bitPattern = bitPattern, .waitMode = waitMode};
if (auto patValue = value.load(std::memory_order::relaxed);
waitingThread.test(patValue)) {
auto resultValue = waitingThread.applyClear(patValue);
value.store(resultValue, std::memory_order::relaxed);
thread->evfResultPattern = patValue;
// Success
break;
} else if (timeout && *timeout == 0) {
thread->evfResultPattern = patValue;
return ErrorCode::TIMEDOUT;
}
if (attrs & kEvfAttrSingle) {
if (!waitingThreads.empty())
return ErrorCode::PERM;
} else {
if (attrs & kEvfAttrThFifo) {
} else {
// FIXME: sort waitingThreads by priority
}
}
waitingThreads.emplace_back(waitingThread);
{
orbis::scoped_unblock unblock;
if (timeout) {
result = toErrorCode(thread->sync_cv.wait(queueMtx, *timeout));
update_timeout();
} else {
result = toErrorCode(thread->sync_cv.wait(queueMtx));
}
}
if (thread->evfIsCancelled == UINT64_MAX) {
std::erase(waitingThreads, waitingThread);
}
}
// TODO: update thread state
return ErrorCode{result};
}
orbis::ErrorCode orbis::EventFlag::tryWait(Thread *thread,
std::uint8_t waitMode,
std::uint64_t bitPattern) {
writer_lock lock(queueMtx);
if (isDeleted) {
return ErrorCode::ACCES;
}
auto waitingThread =
WaitingThread{.bitPattern = bitPattern, .waitMode = waitMode};
if (auto patValue = value.load(std::memory_order::relaxed);
waitingThread.test(patValue)) {
auto resultValue = waitingThread.applyClear(patValue);
value.store(resultValue, std::memory_order::relaxed);
thread->evfResultPattern = patValue;
return {};
}
return ErrorCode::BUSY;
}
std::size_t orbis::EventFlag::notify(NotifyType type, std::uint64_t bits) {
writer_lock lock(queueMtx);
auto patValue = value.load(std::memory_order::relaxed);
if (type == NotifyType::Destroy) {
isDeleted = true;
} else if (type == NotifyType::Set) {
patValue |= bits;
}
auto testThread = [&](WaitingThread *thread) {
if (type == NotifyType::Set && !thread->test(patValue)) {
return false;
}
auto resultValue = thread->applyClear(patValue);
thread->thread->evfResultPattern = patValue;
thread->thread->evfIsCancelled = type == NotifyType::Cancel;
patValue = resultValue;
// TODO: update thread state
// release wait on waiter thread
thread->thread->sync_cv.notify_all(queueMtx);
return true;
};
std::size_t result = std::erase_if(
waitingThreads, [&](auto &thread) { return testThread(&thread); });
if (type == NotifyType::Cancel) {
value.store(bits, std::memory_order::relaxed);
} else {
value.store(patValue, std::memory_order::relaxed);
}
return result;
}

1405
kernel/orbis/src/ipmi.cpp Normal file

File diff suppressed because it is too large Load diff

415
kernel/orbis/src/module.cpp Normal file
View file

@ -0,0 +1,415 @@
#include "module/Module.hpp"
#include "KernelAllocator.hpp"
#include "thread.hpp"
#include <utility>
#include "thread/Process.hpp"
#include <string_view>
// TODO: move relocations to the platform specific code
enum RelType {
kRelNone,
kRel64,
kRelPc32,
kRelGot32,
kRelPlt32,
kRelCopy,
kRelGlobDat,
kRelJumpSlot,
kRelRelative,
kRelGotPcRel,
kRel32,
kRel32s,
kRel16,
kRelPc16,
kRel8,
kRelPc8,
kRelDtpMod64,
kRelDtpOff64,
kRelTpOff64,
kRelTlsGd,
kRelTlsLd,
kRelDtpOff32,
kRelGotTpOff,
kRelTpOff32,
kRelPc64,
kRelGotOff64,
kRelGotPc32,
kRelGot64,
kRelGotPcRel64,
kRelGotPc64,
kRelGotPlt64,
kRelPltOff64,
kRelSize32,
kRelSize64,
kRelGotPc32TlsDesc,
kRelTlsDescCall,
kRelTlsDesc,
kRelIRelative,
kRelRelative64,
};
static std::uint64_t calculateTlsOffset(std::uint64_t prevOffset,
std::uint64_t size,
std::uint64_t align) {
return (prevOffset + size + align - 1) & ~(align - 1);
}
static void allocateTlsOffset(orbis::Process *process, orbis::Module *module) {
if (module->isTlsDone) {
return;
}
auto offset =
calculateTlsOffset(module->tlsIndex == 1 ? 0 : process->lastTlsOffset,
module->tlsSize, module->tlsAlign);
module->tlsOffset = offset;
process->lastTlsOffset = offset;
module->isTlsDone = true;
}
static orbis::SysResult doPltRelocation(orbis::Process *process,
orbis::Module *module,
orbis::Relocation rel) {
auto symbol = module->symbols.at(rel.symbolIndex);
auto A = rel.addend;
auto B = reinterpret_cast<std::uint64_t>(module->base);
auto where = reinterpret_cast<std::uint64_t *>(B + rel.offset);
auto where32 = reinterpret_cast<std::uint32_t *>(B + rel.offset);
auto P = reinterpret_cast<std::uintptr_t>(where);
auto findDefModule = [module,
symbol] -> std::pair<orbis::Module *, std::uint64_t> {
if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) {
return std::pair(module, symbol.address);
}
auto &defModule = module->importedModules.at(symbol.moduleIndex);
if (!defModule) {
// std::printf(
// "Delaying plt relocation '%s' ('%s'), symbol '%llx' in %s
// module\n", module->moduleName, module->soName, (unsigned long
// long)symbol.id,
// module->neededModules[symbol.moduleIndex].name.c_str());
return {};
}
auto library = module->neededLibraries.at(symbol.libraryIndex);
std::vector<std::string> foundInLibs;
for (auto defSym : defModule->symbols) {
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
continue;
}
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
std::printf("Ignoring hidden symbol\n");
continue;
}
auto defLib = defModule->neededLibraries.at(defSym.libraryIndex);
if (defLib.name == library.name) {
return std::pair(defModule.get(), defSym.address);
}
foundInLibs.emplace_back(std::string_view(defLib.name));
}
for (auto nsDefModule : defModule->namespaceModules) {
for (auto defSym : nsDefModule->symbols) {
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
continue;
}
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
std::printf("Ignoring hidden symbol\n");
continue;
}
auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex);
if (defLib.name == library.name) {
return std::pair(nsDefModule.get(), defSym.address);
}
}
}
std::printf(
"'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n",
module->moduleName, module->soName, (unsigned long long)symbol.id,
defModule->moduleName, defModule->soName);
if (foundInLibs.size() > 0) {
std::printf("Requested library is '%s', exists in libraries: [",
library.name.c_str());
for (bool isFirst = true; auto &lib : foundInLibs) {
if (isFirst) {
isFirst = false;
} else {
std::printf(", ");
}
std::printf("'%s'", lib.c_str());
}
std::printf("]\n");
}
return std::pair(module, symbol.address);
};
switch (rel.relType) {
case kRelJumpSlot: {
bool isLazyBind = false; // TODO
if (isLazyBind) {
*where += B;
} else {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where = S ? reinterpret_cast<std::uintptr_t>(defObj->base) + S : 0;
}
return {};
}
}
std::fprintf(stderr, "unimplemented relocation type %u\n",
(unsigned)rel.relType);
std::abort();
return {};
}
static orbis::SysResult doRelocation(orbis::Process *process,
orbis::Module *module,
orbis::Relocation rel) {
auto symbol = module->symbols.at(rel.symbolIndex);
auto A = rel.addend;
auto B = reinterpret_cast<std::uint64_t>(module->base);
auto where = reinterpret_cast<std::uint64_t *>(B + rel.offset);
auto where32 = reinterpret_cast<std::uint32_t *>(B + rel.offset);
auto P = reinterpret_cast<std::uintptr_t>(where);
auto findDefModule = [module, symbol,
rel] -> std::pair<orbis::Module *, std::uint64_t> {
if (symbol.moduleIndex == -1 || symbol.bind == orbis::SymbolBind::Local) {
return std::pair(module, symbol.address);
}
auto &defModule = module->importedModules.at(symbol.moduleIndex);
if (!defModule) {
// std::printf("'%s' ('%s') uses undefined symbol '%llx' in unloaded
// module "
// "'%s', rel %u\n",
// module->moduleName, module->soName,
// (unsigned long long)symbol.id,
// module->neededModules.at(symbol.moduleIndex).name.c_str(),
// rel.relType);
return {};
}
auto library = module->neededLibraries.at(symbol.libraryIndex);
std::vector<std::string> foundInLibs;
for (auto defSym : defModule->symbols) {
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
continue;
}
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
std::printf("Ignoring hidden symbol\n");
continue;
}
auto defLib = defModule->neededLibraries.at(defSym.libraryIndex);
if (defLib.name == library.name) {
return std::pair(defModule.get(), defSym.address);
}
foundInLibs.emplace_back(std::string_view(defLib.name));
}
for (auto nsDefModule : defModule->namespaceModules) {
for (auto defSym : nsDefModule->symbols) {
if (defSym.id != symbol.id || defSym.bind == orbis::SymbolBind::Local) {
continue;
}
if (defSym.visibility == orbis::SymbolVisibility::Hidden) {
std::printf("Ignoring hidden symbol\n");
continue;
}
auto defLib = nsDefModule->neededLibraries.at(defSym.libraryIndex);
if (defLib.name == library.name) {
return std::pair(nsDefModule.get(), defSym.address);
}
}
}
std::printf(
"'%s' ('%s') uses undefined symbol '%llx' in '%s' ('%s') module\n",
module->moduleName, module->soName, (unsigned long long)symbol.id,
defModule->moduleName, defModule->soName);
if (foundInLibs.size() > 0) {
std::printf("Requested library is '%s', exists in libraries: [",
library.name.c_str());
for (bool isFirst = true; auto &lib : foundInLibs) {
if (isFirst) {
isFirst = false;
} else {
std::printf(", ");
}
std::printf("'%s'", lib.c_str());
}
std::printf("]\n");
}
return std::pair(module, symbol.address);
};
switch (rel.relType) {
case kRelNone:
return {};
case kRel64: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where = S ? reinterpret_cast<std::uintptr_t>(defObj->base) + S + A : 0;
return {};
}
return {};
case kRelPc32: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where32 =
S ? reinterpret_cast<std::uintptr_t>(defObj->base) + S + A - P : 0;
return {};
}
// case kRelCopy:
// return{};
case kRelGlobDat: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where = S ? reinterpret_cast<std::uintptr_t>(defObj->base) + S : 0;
return {};
}
case kRelRelative:
*where = B + A;
return {};
case kRelDtpMod64: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where += defObj->tlsIndex;
return {};
}
case kRelDtpOff64: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
*where += S + A;
return {};
}
case kRelTpOff64: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
if (!defObj->isTlsDone) {
allocateTlsOffset(process, defObj);
}
*where = S - defObj->tlsOffset + A;
return {};
}
case kRelDtpOff32: {
auto [defObj, S] = findDefModule();
*where32 += S + A;
return {};
}
case kRelTpOff32: {
auto [defObj, S] = findDefModule();
if (defObj == nullptr) {
return orbis::ErrorCode::INVAL;
}
if (!defObj->isTlsDone) {
allocateTlsOffset(process, defObj);
}
*where32 = S - defObj->tlsOffset + A;
return {};
}
}
std::fprintf(stderr, "unimplemented relocation type %u\n",
(unsigned)rel.relType);
std::abort();
return {};
}
orbis::SysResult orbis::Module::relocate(Process *process) {
if (!pltRelocations.empty()) {
kvector<Relocation> delayedRelocations;
std::size_t resolved = 0;
std::size_t delayed = 0;
for (auto rel : pltRelocations) {
auto result = doPltRelocation(process, this, rel);
if (result.isError()) {
delayedRelocations.push_back(rel);
++delayed;
} else {
++resolved;
}
}
std::printf("plt relocation of %s: delayed/resolved: %zu/%zu\n", moduleName,
delayed, resolved);
pltRelocations = std::move(delayedRelocations);
}
if (!nonPltRelocations.empty()) {
kvector<Relocation> delayedRelocations;
std::size_t resolved = 0;
std::size_t delayed = 0;
for (auto rel : nonPltRelocations) {
auto result = doRelocation(process, this, rel);
if (result.isError()) {
delayedRelocations.push_back(rel);
++delayed;
} else {
++resolved;
}
}
std::printf("non-plt relocation of %s: delayed/resolved: %zu/%zu\n",
moduleName, delayed, resolved);
nonPltRelocations = std::move(delayedRelocations);
}
return {};
}
void orbis::Module::destroy() {
std::lock_guard lock(proc->mtx);
proc->modulesMap.close(id);
}

95
kernel/orbis/src/pipe.cpp Normal file
View file

@ -0,0 +1,95 @@
#include "pipe.hpp"
#include "error/ErrorCode.hpp"
#include "file.hpp"
#include "thread/Thread.hpp"
#include "uio.hpp"
#include "utils/Logs.hpp"
#include <span>
static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio,
orbis::Thread *thread) {
auto pipe = static_cast<orbis::Pipe *>(file);
while (true) {
if (pipe->data.empty()) {
// pipe->cv.wait(file->mtx);
// ORBIS_LOG_ERROR(__FUNCTION__, "wakeup", thread->name, thread->tid,
// file); continue;
return orbis::ErrorCode::WOULDBLOCK;
}
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
auto size = std::min<std::size_t>(pipe->data.size(), vec.len);
if (size == 0) {
pipe->data.clear();
continue;
}
if (size > pipe->data.size()) {
size = pipe->data.size();
}
uio->offset += size;
std::memcpy(vec.base, pipe->data.data(), size);
ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, size,
pipe->data.size(), uio->offset, file->nextOff);
if (pipe->data.size() == size) {
pipe->data.clear();
break;
}
std::memmove(pipe->data.data(), pipe->data.data() + size,
pipe->data.size() - size);
pipe->data.resize(pipe->data.size() - size);
}
break;
}
pipe->event->emit(orbis::kEvFiltWrite);
return {};
}
static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio,
orbis::Thread *thread) {
auto pipe = static_cast<orbis::Pipe *>(file)->other;
ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file);
std::size_t cnt = 0;
for (auto vec : std::span(uio->iov, uio->iovcnt)) {
auto offset = pipe->data.size();
pipe->data.resize(offset + vec.len);
ORBIS_RET_ON_ERROR(orbis::ureadRaw(pipe->data.data(), vec.base, vec.len));
cnt += vec.len;
}
pipe->event->emit(orbis::kEvFiltRead);
pipe->cv.notify_one(file->mtx);
uio->resid -= cnt;
uio->offset += cnt;
ORBIS_LOG_ERROR(__FUNCTION__, thread->name, thread->tid, file, uio->resid,
uio->offset, file->nextOff, cnt);
thread->where();
return {};
}
static orbis::FileOps pipe_ops = {
.read = pipe_read,
.write = pipe_write,
};
std::pair<orbis::Ref<orbis::Pipe>, orbis::Ref<orbis::Pipe>>
orbis::createPipe() {
auto a = knew<Pipe>();
auto b = knew<Pipe>();
a->event = knew<EventEmitter>();
b->event = knew<EventEmitter>();
a->ops = &pipe_ops;
b->ops = &pipe_ops;
a->other = b;
b->other = a;
return {a, b};
}

View file

@ -0,0 +1,6 @@
#include "error.hpp"
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_acct(Thread *thread, ptr<char> path) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,35 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_audit(Thread *thread, ptr<const void> record,
uint length) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_auditon(Thread *thread, sint cmd, ptr<void> data,
uint length) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getauid(Thread *thread, ptr<uid_t> auid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setauid(Thread *thread, ptr<uid_t> auid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getaudit(Thread *thread,
ptr<struct auditinfo> auditinfo) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setaudit(Thread *thread,
ptr<struct auditinfo> auditinfo) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getaudit_addr(
Thread *thread, ptr<struct auditinfo_addr> auditinfo_addr, uint length) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setaudit_addr(
Thread *thread, ptr<struct auditinfo_addr> auditinfo_addr, uint length) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_auditctl(Thread *thread, ptr<char> path) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,15 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_cap_enter(Thread *thread) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cap_getmode(Thread *thread, ptr<uint> modep) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cap_new(Thread *thread, sint fd, uint64_t rights) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cap_getrights(Thread *thread, sint fd,
ptr<uint64_t> rights) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,12 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_getcontext(Thread *thread, ptr<UContext> ucp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setcontext(Thread *thread, ptr<UContext> ucp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_swapcontext(Thread *thread, ptr<UContext> oucp,
ptr<UContext> ucp) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,195 @@
#include "KernelContext.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "thread/cpuset.hpp"
#include "utils/Logs.hpp"
#include <bit>
#include <pthread.h>
#include <sched.h>
#include <sys/sysinfo.h>
enum class CpuLevel {
Root = 1,
CpuSet = 2,
Which = 3,
};
enum class CpuWhich {
Tid = 1,
Pid = 2,
CpuSet = 3,
Irq = 4,
Jail = 5,
};
static cpu_set_t toHostCpuSet(orbis::cpuset cpuSet) {
const int procCount = get_nprocs();
cpu_set_t result{};
for (unsigned cpu = std::countr_zero(cpuSet.bits);
cpu < sizeof(cpuSet.bits) * 8;
cpu = std::countr_zero(cpuSet.bits >> (cpu + 1)) + cpu + 1) {
unsigned hostCpu = cpu;
if (procCount < 8) {
hostCpu = cpu % procCount;
} else if (procCount >= 8 * 2) {
hostCpu = cpu * 2;
}
ORBIS_LOG_ERROR(__FUNCTION__, cpu, hostCpu);
CPU_SET(hostCpu, &result);
}
ORBIS_LOG_ERROR(__FUNCTION__, procCount, result.__bits[0], cpuSet.bits);
return result;
}
orbis::SysResult orbis::sys_cpuset(Thread *thread, ptr<cpusetid_t> setid) {
return {};
}
orbis::SysResult orbis::sys_cpuset_setid(Thread *thread, cpuwhich_t which,
id_t id, cpusetid_t setid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cpuset_getid(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
ptr<cpusetid_t> setid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_cpuset_getaffinity(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
size_t cpusetsize,
ptr<cpuset> mask) {
if (cpusetsize < sizeof(cpuset)) {
return ErrorCode::INVAL;
}
std::lock_guard lock(thread->mtx);
std::lock_guard lockProc(thread->tproc->mtx);
switch (CpuLevel{level}) {
case CpuLevel::Root:
case CpuLevel::CpuSet:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
case CpuLevel::Which:
switch (CpuWhich(which)) {
case CpuWhich::Tid: {
Thread *whichThread = nullptr;
if (id == ~id_t(0) || thread->tid == id) {
whichThread = thread;
} else {
whichThread = thread->tproc->threadsMap.get(id - thread->tproc->pid);
if (whichThread == nullptr) {
ORBIS_LOG_ERROR(__FUNCTION__, "thread not found", level, which, id,
cpusetsize);
return ErrorCode::SRCH;
}
}
return uwrite(mask, whichThread->affinity);
}
case CpuWhich::Pid: {
Process *whichProcess = nullptr;
if (id == ~id_t(0) || id == thread->tproc->pid) {
whichProcess = thread->tproc;
} else {
whichProcess = g_context.findProcessById(id);
if (whichProcess == nullptr) {
return ErrorCode::SRCH;
}
}
return uwrite(mask, whichProcess->affinity);
}
case CpuWhich::CpuSet:
case CpuWhich::Irq:
case CpuWhich::Jail:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
}
break;
}
return ErrorCode::INVAL;
}
orbis::SysResult orbis::sys_cpuset_setaffinity(Thread *thread, cpulevel_t level,
cpuwhich_t which, id_t id,
size_t cpusetsize,
ptr<const cpuset> mask) {
std::lock_guard lock(thread->mtx);
std::lock_guard lockProc(thread->tproc->mtx);
switch (CpuLevel{level}) {
case CpuLevel::Root:
case CpuLevel::CpuSet:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
case CpuLevel::Which:
switch (CpuWhich(which)) {
case CpuWhich::Tid: {
Thread *whichThread = nullptr;
if (id == ~id_t(0) || thread->tid == id) {
whichThread = thread;
} else {
whichThread = thread->tproc->threadsMap.get(id - thread->tproc->pid);
if (whichThread == nullptr) {
ORBIS_LOG_ERROR(__FUNCTION__, "thread not found", level, which, id,
cpusetsize);
return ErrorCode::SRCH;
}
}
ORBIS_RET_ON_ERROR(uread(whichThread->affinity, mask));
auto threadHandle = whichThread->getNativeHandle();
auto hostCpuSet = toHostCpuSet(whichThread->affinity);
ORBIS_LOG_ERROR(__FUNCTION__, threadHandle, thread->tid, id);
if (pthread_setaffinity_np(threadHandle, sizeof(hostCpuSet),
&hostCpuSet)) {
ORBIS_LOG_ERROR(__FUNCTION__,
"failed to set affinity mask for host thread",
whichThread->hostTid, whichThread->affinity.bits);
}
return {};
}
case CpuWhich::Pid: {
Process *whichProcess = nullptr;
if (id == ~id_t(0) || id == thread->tproc->pid) {
whichProcess = thread->tproc;
} else {
ORBIS_LOG_ERROR(__FUNCTION__, "process not found", level, which, id,
cpusetsize);
whichProcess = g_context.findProcessById(id);
if (whichProcess == nullptr) {
return ErrorCode::SRCH;
}
}
ORBIS_RET_ON_ERROR(uread(whichProcess->affinity, mask));
auto hostCpuSet = toHostCpuSet(whichProcess->affinity);
if (sched_setaffinity(whichProcess->hostPid, sizeof(hostCpuSet),
&hostCpuSet)) {
ORBIS_LOG_ERROR(__FUNCTION__,
"failed to set affinity mask for host process",
whichProcess->hostPid, whichProcess->affinity.bits);
}
return {};
}
case CpuWhich::CpuSet:
case CpuWhich::Irq:
case CpuWhich::Jail:
ORBIS_LOG_ERROR(__FUNCTION__, level, which, id, cpusetsize);
return ErrorCode::INVAL;
}
break;
}
return ErrorCode::INVAL;
}

View file

@ -0,0 +1,80 @@
#include "file.hpp"
#include "orbis/utils/Logs.hpp"
#include "stat.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
orbis::SysResult orbis::sys_getdtablesize(Thread *thread) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_dup2(Thread *thread, uint from, uint to) {
auto file = thread->tproc->fileDescriptors.get(from);
if (file == nullptr) {
return ErrorCode::BADF;
}
thread->tproc->fileDescriptors.close(to);
thread->tproc->fileDescriptors.insert(to, file);
return {};
}
orbis::SysResult orbis::sys_dup(Thread *thread, uint fd) {
auto file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
thread->retval[0] = thread->tproc->fileDescriptors.insert(std::move(file));
return {};
}
orbis::SysResult orbis::sys_fcntl(Thread *thread, sint fd, sint cmd,
slong arg) {
ORBIS_LOG_TODO(__FUNCTION__, fd, cmd, arg);
return {};
}
orbis::SysResult orbis::sys_close(Thread *thread, sint fd) {
// ORBIS_LOG_NOTICE(__FUNCTION__, fd);
if (thread->tproc->fileDescriptors.close(fd)) {
return {};
}
return ErrorCode::BADF;
}
orbis::SysResult orbis::sys_closefrom(Thread *thread, sint lowfd) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fstat(Thread *thread, sint fd, ptr<Stat> ub) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto stat = file->ops->stat;
if (stat == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Stat _ub;
auto result = uread(_ub, ub);
if (result != ErrorCode{}) {
return result;
}
result = stat(file.get(), &_ub, thread);
if (result != ErrorCode{}) {
return result;
}
return uwrite(ub, _ub);
}
orbis::SysResult orbis::sys_nfstat(Thread *thread, sint fd,
ptr<struct nstat> sb) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fpathconf(Thread *thread, sint fd, sint name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_flock(Thread *thread, sint fd, sint how) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,86 @@
#include "sys/sysproto.hpp"
#include "KernelContext.hpp"
#include "thread/Process.hpp"
orbis::SysResult orbis::sys_kenv(Thread *thread, sint what,
ptr<const char> name, ptr<char> value,
sint len) {
enum action { kenv_get, kenv_set, kenv_unset, kenv_dump };
const auto &[kenv, _] = thread->tproc->context->getKernelEnv();
if (what == kenv_dump) {
int needed = 0;
int done = 0;
for (const auto &[key, env_value] : kenv) {
size_t entry = 0;
// Entry: size of both full buffers, the '=' and the '\0' at the end
if (value == nullptr || len == 0) {
entry = key.size() + 1 + strnlen(env_value, 128) + 1;
} else {
char buf[128 * 2 + 2];
char *_buf = buf;
std::strncpy(buf, key.data(), key.size());
_buf += key.size();
*_buf++ = '=';
const size_t value_size = strnlen(env_value, 128);
std::strncpy(_buf, env_value, value_size);
_buf += value_size;
*_buf++ = '\0';
entry = _buf - buf;
ORBIS_RET_ON_ERROR(uwriteRaw(value + done, buf, entry));
len -= entry;
done += entry;
}
needed += entry;
}
if (done != needed) {
thread->retval[0] = needed;
}
return {};
}
char _name_buf[128];
ORBIS_RET_ON_ERROR(ureadString(_name_buf, sizeof(_name_buf), name));
const std::string_view _name(_name_buf, strnlen(_name_buf, 128));
switch (what) {
case kenv_get: {
const auto it = kenv.find(_name);
if (it == kenv.end()) {
return ErrorCode::NOENT;
}
const char *buf = it->second;
ORBIS_RET_ON_ERROR(uwriteRaw(value, buf, std::min(len, 128)));
break;
}
case kenv_set: {
if (len < 1) {
return ErrorCode::INVAL;
}
char *_value_buf = kenv[kstring(_name)];
ORBIS_RET_ON_ERROR(ureadString(_value_buf, 128, value));
break;
}
case kenv_unset: {
const auto it = kenv.find(_name);
if (it == kenv.end()) {
return ErrorCode::NOENT;
}
kenv.erase(it);
break;
}
default:
return ErrorCode::INVAL;
}
return {};
}

View file

@ -0,0 +1,402 @@
#include "KernelAllocator.hpp"
#include "KernelContext.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "utils/Logs.hpp"
#include <chrono>
#include <list>
#include <span>
#include <sys/select.h>
orbis::SysResult orbis::sys_kqueue(Thread *thread) {
auto queue = knew<KQueue>();
if (queue == nullptr) {
return ErrorCode::NOMEM;
}
auto fd = thread->tproc->fileDescriptors.insert(queue);
ORBIS_LOG_TODO(__FUNCTION__, fd);
thread->retval[0] = fd;
return {};
}
orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr<char> name,
sint flags) {
auto queue = knew<KQueue>();
if (queue == nullptr) {
return ErrorCode::NOMEM;
}
auto fd = thread->tproc->fileDescriptors.insert(queue);
if (name != nullptr) {
queue->name = name;
}
ORBIS_LOG_TODO(__FUNCTION__, name, flags, fd);
thread->retval[0] = fd;
return {};
}
static bool isReadEventTriggered(int hostFd) {
fd_set fds{};
FD_SET(hostFd, &fds);
timeval timeout{};
if (::select(hostFd + 1, &fds, nullptr, nullptr, &timeout) < 0) {
return false;
}
return FD_ISSET(hostFd, &fds);
}
static bool isWriteEventTriggered(int hostFd) {
fd_set fds{};
FD_SET(hostFd, &fds);
timeval timeout{};
if (::select(hostFd + 1, nullptr, &fds, nullptr, &timeout) < 0) {
return false;
}
return FD_ISSET(hostFd, &fds);
}
namespace orbis {
static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) {
auto nodeIt = kq->notes.end();
for (auto it = kq->notes.begin(); it != kq->notes.end(); ++it) {
if (it->event.ident == change.ident && it->event.filter == change.filter) {
nodeIt = it;
break;
}
}
if (change.flags & kEvDelete) {
if (nodeIt == kq->notes.end()) {
return orbis::ErrorCode::NOENT;
}
kq->notes.erase(nodeIt);
nodeIt = kq->notes.end();
}
std::unique_lock<shared_mutex> noteLock;
if (change.flags & kEvAdd) {
if (nodeIt == kq->notes.end()) {
auto &note = kq->notes.emplace_front();
note.event.flags &= ~(kEvAdd | kEvDelete | kEvDisable | kEvEnable);
note.queue = kq;
note.event = change;
note.enabled = true;
nodeIt = kq->notes.begin();
if (change.filter == kEvFiltProc) {
auto process = g_context.findProcessById(change.ident);
if (process == nullptr) {
return ErrorCode::SRCH;
}
noteLock = std::unique_lock(nodeIt->mutex);
std::unique_lock lock(process->event.mutex);
process->event.notes.insert(&*nodeIt);
nodeIt->linked = process;
if ((change.fflags & orbis::kNoteExit) != 0 &&
process->exitStatus.has_value()) {
note.event.data = *process->exitStatus;
note.triggered = true;
kq->cv.notify_all(kq->mtx);
}
} else if (change.filter == kEvFiltRead ||
change.filter == kEvFiltWrite) {
auto fd = thread->tproc->fileDescriptors.get(change.ident);
if (fd == nullptr) {
return ErrorCode::BADF;
}
nodeIt->file = fd;
if (auto eventEmitter = fd->event) {
eventEmitter->subscribe(&*nodeIt);
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
} else if (note.file->hostFd < 0) {
ORBIS_LOG_ERROR("Unimplemented event emitter", change.ident);
}
} else if (change.filter == kEvFiltGraphicsCore ||
change.filter == kEvFiltDisplay) {
g_context.deviceEventEmitter->subscribe(&*nodeIt);
}
}
}
if (nodeIt == kq->notes.end()) {
if (change.flags & kEvDelete) {
return {};
}
return orbis::ErrorCode::NOENT;
}
if (change.filter == kEvFiltDisplay || change.filter == kEvFiltGraphicsCore) {
change.flags |= kEvClear;
}
if (!noteLock.owns_lock()) {
noteLock = std::unique_lock(nodeIt->mutex);
}
if (change.flags & kEvDisable) {
nodeIt->enabled = false;
}
if (change.flags & kEvEnable) {
nodeIt->enabled = true;
}
if (change.flags & kEvClear) {
nodeIt->triggered = false;
}
if (change.filter == kEvFiltUser) {
auto fflags = 0;
switch (change.fflags & kNoteFFCtrlMask) {
case kNoteFFAnd:
fflags = nodeIt->event.fflags & change.fflags;
break;
case kNoteFFOr:
fflags = nodeIt->event.fflags | change.fflags;
break;
case kNoteFFCopy:
fflags = change.fflags;
break;
}
nodeIt->event.fflags =
(nodeIt->event.fflags & ~kNoteFFlagsMask) | (fflags & kNoteFFlagsMask);
if (change.fflags & kNoteTrigger) {
nodeIt->event.udata = change.udata;
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
} else if (change.filter == kEvFiltDisplay && change.ident >> 48 == 0x6301) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
} else if (change.filter == kEvFiltGraphicsCore && change.ident == 0x84) {
nodeIt->triggered = true;
nodeIt->event.data |= 1000ull << 16; // clock
kq->cv.notify_all(kq->mtx);
} else if (g_context.fwType == FwType::Ps5 &&
change.filter == kEvFiltGraphicsCore && change.ident == 0) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
return {};
}
static orbis::ErrorCode ureadTimespec(orbis::timespec &ts,
orbis::ptr<const orbis::timespec> addr) {
orbis::ErrorCode error = uread(ts, addr);
if (error != orbis::ErrorCode{})
return error;
if (ts.sec < 0 || ts.nsec < 0 || ts.nsec > 1000000000) {
return orbis::ErrorCode::INVAL;
}
return {};
}
} // namespace orbis
orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd,
ptr<KEvent> changelist, sint nchanges,
ptr<KEvent> eventlist, sint nevents,
ptr<const timespec> timeout) {
// ORBIS_LOG_TODO(__FUNCTION__, fd, changelist, nchanges, eventlist, nevents,
// timeout);
auto kq = thread->tproc->fileDescriptors.get(fd).cast<KQueue>();
if (kq == nullptr) {
return orbis::ErrorCode::BADF;
}
{
std::lock_guard lock(kq->mtx);
if (nchanges != 0) {
for (auto &changePtr : std::span(changelist, nchanges)) {
KEvent change;
ORBIS_RET_ON_ERROR(uread(change, &changePtr));
if (change.filter != kEvFiltUser) {
ORBIS_LOG_NOTICE(__FUNCTION__, fd, change.ident, change.filter,
change.flags, change.fflags, change.data,
change.udata);
}
if (auto result = keventChange(kq.get(), change, thread);
result.value() != 0) {
return result;
}
}
kq->cv.notify_all(kq->mtx);
}
}
if (nevents == 0) {
return {};
}
using clock = std::chrono::high_resolution_clock;
clock::time_point timeoutPoint = clock::time_point::max();
if (timeout != nullptr) {
timespec _timeout;
auto result = ureadTimespec(_timeout, timeout);
if (result != ErrorCode{}) {
return result;
}
__uint128_t nsec = _timeout.sec;
nsec *= 1000'000'000;
nsec += _timeout.nsec;
if (nsec < INT64_MAX) {
auto now = clock::now();
auto nowValue = now.time_since_epoch().count();
if (nowValue <= nowValue + nsec) {
timeoutPoint = now + std::chrono::nanoseconds(nsec);
}
}
}
std::vector<KEvent> result;
result.reserve(nevents);
ErrorCode errorCode{};
while (true) {
bool canSleep = true;
{
std::lock_guard lock(kq->mtx);
while (result.size() < nevents && !kq->triggeredEvents.empty()) {
result.push_back(kq->triggeredEvents.back());
kq->triggeredEvents.pop_back();
}
if (result.empty()) {
for (auto it = kq->notes.begin(); it != kq->notes.end();) {
auto &note = *it;
bool erase = false;
{
std::lock_guard lock(note.mutex);
if (!note.triggered) {
if (note.event.filter == kEvFiltRead) {
if (note.file->hostFd >= 0) {
if (isReadEventTriggered(note.file->hostFd)) {
note.triggered = true;
} else {
canSleep = false;
}
}
} else if (note.event.filter == kEvFiltWrite) {
if (note.file->hostFd >= 0) {
if (isWriteEventTriggered(note.file->hostFd)) {
note.triggered = true;
} else {
canSleep = false;
}
}
}
}
if (note.enabled && note.triggered) {
result.push_back(note.event);
if (note.event.filter == kEvFiltDisplay) {
note.triggered = false;
} else if (note.event.filter == kEvFiltGraphicsCore &&
note.event.ident != 0x84) {
note.triggered = false;
}
if (note.event.flags & kEvDispatch) {
note.enabled = false;
}
if (note.event.flags & kEvOneshot) {
erase = true;
}
if (note.event.filter == kEvFiltRead ||
note.event.filter == kEvFiltWrite) {
note.triggered = false;
}
}
}
if (erase) {
it = kq->notes.erase(it);
} else {
++it;
}
}
while (result.size() > nevents) {
kq->triggeredEvents.push_back(result.back());
result.pop_back();
}
}
}
if (!result.empty()) {
break;
}
if (timeoutPoint != clock::time_point::max()) {
std::lock_guard lock(kq->mtx);
auto now = clock::now();
if (now >= timeoutPoint) {
errorCode = ErrorCode::TIMEDOUT;
break;
}
auto waitTimeout = std::chrono::duration_cast<std::chrono::microseconds>(
timeoutPoint - now);
if (canSleep) {
if (waitTimeout.count() > 1000) {
orbis::scoped_unblock unblock;
kq->cv.wait(kq->mtx, waitTimeout.count());
} else {
kq->cv.wait(kq->mtx, waitTimeout.count());
}
}
} else {
if (canSleep) {
std::lock_guard lock(kq->mtx);
orbis::scoped_unblock unblock;
kq->cv.wait(kq->mtx);
} else {
std::this_thread::sleep_for(std::chrono::microseconds(30));
}
}
}
// ORBIS_LOG_TODO(__FUNCTION__, "kevent wakeup", fd);
// for (auto evt : result) {
// ORBIS_LOG_TODO(__FUNCTION__,
// evt.ident,
// evt.filter,
// evt.flags,
// evt.fflags,
// evt.data,
// evt.udata
// );
// }
ORBIS_RET_ON_ERROR(
uwriteRaw(eventlist, result.data(), result.size() * sizeof(KEvent)));
thread->retval[0] = result.size();
return {};
}

View file

@ -0,0 +1,23 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
orbis::SysResult orbis::sys_execve(Thread *thread, ptr<char> fname,
ptr<ptr<char>> argv, ptr<ptr<char>> envv) {
if (auto execve = thread->tproc->ops->execve) {
return execve(thread, fname, argv, envv);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fexecve(Thread *thread, sint fd,
ptr<ptr<char>> argv, ptr<ptr<char>> envv) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_execve(Thread *thread, ptr<char> fname,
ptr<ptr<char>> argv,
ptr<ptr<char>> envv,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,59 @@
#include "KernelContext.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "utils/Logs.hpp"
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
orbis::SysResult orbis::sys_exit(Thread *thread, sint status) {
if (auto exit = thread->tproc->ops->exit) {
return exit(thread, status);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_abort2(Thread *thread, ptr<const char> why,
sint narg, ptr<ptr<void>> args) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_wait4(Thread *thread, sint pid, ptr<sint> status,
sint options, ptr<struct rusage> rusage) {
// TODO
ORBIS_LOG_ERROR(__FUNCTION__, pid, status, options, rusage);
int hostPid = pid;
if (pid > 0) {
auto process = g_context.findProcessById(pid);
if (process == nullptr) {
return ErrorCode::SRCH;
}
hostPid = process->hostPid;
}
::rusage hostUsage;
while (true) {
int stat;
int result = ::wait4(hostPid, &stat, options, &hostUsage);
if (result < 0) {
return static_cast<ErrorCode>(errno);
}
ORBIS_LOG_ERROR(__FUNCTION__, pid, status, options, rusage, result, stat);
auto process = g_context.findProcessByHostId(result);
if (process == nullptr) {
ORBIS_LOG_ERROR("host process not found", result);
continue;
}
if (status != nullptr) {
ORBIS_RET_ON_ERROR(uwrite(status, stat));
}
thread->retval[0] = process->pid;
break;
}
return {};
}

View file

@ -0,0 +1,24 @@
#include "KernelContext.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include <cstdlib>
#include <unistd.h>
orbis::SysResult orbis::sys_fork(Thread *thread) {
if (auto fork = thread->tproc->ops->fork) {
return fork(thread, RFFDG | RFPROC);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_pdfork(Thread *thread, ptr<sint> fdp, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_vfork(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_rfork(Thread *thread, sint flags) {
if (auto fork = thread->tproc->ops->fork) {
return fork(thread, flags);
}
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,507 @@
#include "file.hpp"
#include "orbis/utils/Logs.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "uio.hpp"
#include <sstream>
orbis::SysResult orbis::sys_read(Thread *thread, sint fd, ptr<void> buf,
size_t nbyte) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto read = file->ops->read;
if (read == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
IoVec vec{.base = (void *)buf, .len = nbyte};
Uio io{
.offset = file->nextOff,
.iov = &vec,
.iovcnt = 1,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Read,
.td = thread,
};
auto error = read(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
if (error == ErrorCode::BUSY) {
return SysResult::notAnError(error);
}
return error;
}
auto cnt = io.offset - file->nextOff;
file->nextOff = io.offset;
// ORBIS_LOG_ERROR(__FUNCTION__, fd, buf, nbyte, cnt);
thread->retval[0] = cnt;
return {};
}
orbis::SysResult orbis::sys_pread(Thread *thread, sint fd, ptr<void> buf,
size_t nbyte, off_t offset) {
// ORBIS_LOG_ERROR(__FUNCTION__, fd, buf, nbyte, offset);
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto read = file->ops->read;
if (read == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
IoVec vec{.base = (void *)buf, .len = nbyte};
Uio io{
.offset = static_cast<std::uint64_t>(offset),
.iov = &vec,
.iovcnt = 1,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Read,
.td = thread,
};
auto error = read(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
thread->retval[0] = io.offset - offset;
return {};
}
orbis::SysResult orbis::sys_freebsd6_pread(Thread *thread, sint fd,
ptr<void> buf, size_t nbyte, sint,
off_t offset) {
return sys_pread(thread, fd, buf, nbyte, offset);
}
orbis::SysResult orbis::sys_readv(Thread *thread, sint fd, ptr<IoVec> iovp,
uint iovcnt) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto read = file->ops->read;
if (read == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Uio io{
.offset = file->nextOff,
.iov = iovp,
.iovcnt = iovcnt,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Read,
.td = thread,
};
auto error = read(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
auto cnt = io.offset - file->nextOff;
file->nextOff = io.offset;
thread->retval[0] = cnt;
return {};
}
orbis::SysResult orbis::sys_preadv(Thread *thread, sint fd, ptr<IoVec> iovp,
uint iovcnt, off_t offset) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto read = file->ops->read;
if (read == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Uio io{
.offset = static_cast<std::uint64_t>(offset),
.iov = iovp,
.iovcnt = iovcnt,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Read,
.td = thread,
};
auto error = read(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
thread->retval[0] = io.offset - offset;
return {};
}
orbis::SysResult orbis::sys_write(Thread *thread, sint fd, ptr<const void> buf,
size_t nbyte) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto write = file->ops->write;
if (write == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
IoVec vec{.base = (void *)buf, .len = nbyte};
Uio io{
.offset = file->nextOff,
.iov = &vec,
.iovcnt = 1,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Write,
.td = thread,
};
auto error = write(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
auto cnt = io.offset - file->nextOff;
file->nextOff = io.offset;
thread->retval[0] = cnt;
return {};
}
orbis::SysResult orbis::sys_pwrite(Thread *thread, sint fd, ptr<const void> buf,
size_t nbyte, off_t offset) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto write = file->ops->write;
if (write == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
IoVec vec{.base = (void *)buf, .len = nbyte};
Uio io{
.offset = static_cast<std::uint64_t>(offset),
.iov = &vec,
.iovcnt = 1,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Write,
.td = thread,
};
auto error = write(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
thread->retval[0] = io.offset - offset;
return {};
}
orbis::SysResult orbis::sys_freebsd6_pwrite(Thread *thread, sint fd,
ptr<const void> buf, size_t nbyte,
sint, off_t offset) {
return sys_pwrite(thread, fd, buf, nbyte, offset);
}
orbis::SysResult orbis::sys_writev(Thread *thread, sint fd, ptr<IoVec> iovp,
uint iovcnt) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto write = file->ops->write;
if (write == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Uio io{
.offset = file->nextOff,
.iov = iovp,
.iovcnt = iovcnt,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Write,
.td = thread,
};
auto error = write(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
auto cnt = io.offset - file->nextOff;
file->nextOff = io.offset;
thread->retval[0] = cnt;
return {};
}
orbis::SysResult orbis::sys_pwritev(Thread *thread, sint fd, ptr<IoVec> iovp,
uint iovcnt, off_t offset) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto write = file->ops->write;
if (write == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Uio io{
.offset = static_cast<std::uint64_t>(offset),
.iov = iovp,
.iovcnt = iovcnt,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Write,
.td = thread,
};
auto error = write(file.get(), &io, thread);
if (error != ErrorCode{} && error != ErrorCode::AGAIN) {
return error;
}
thread->retval[0] = io.offset - offset;
return {};
}
orbis::SysResult orbis::sys_ftruncate(Thread *thread, sint fd, off_t length) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto truncate = file->ops->truncate;
if (truncate == nullptr) {
return ErrorCode::NOTSUP;
}
ORBIS_LOG_WARNING(__FUNCTION__, fd, length);
std::lock_guard lock(file->mtx);
return truncate(file.get(), length, thread);
}
orbis::SysResult orbis::sys_freebsd6_ftruncate(Thread *thread, sint fd, sint,
off_t length) {
return sys_ftruncate(thread, fd, length);
}
// clang-format off
#define IOCPARM_SHIFT 13 /* number of bits for ioctl size */
#define IOCPARM_MASK ((1 << IOCPARM_SHIFT) - 1) /* parameter length mask */
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << 16))
#define IOCGROUP(x) (((x) >> 8) & 0xff)
#define IOCPARM_MAX (1 << IOCPARM_SHIFT) /* max size of ioctl */
#define IOC_VOID 0x20000000 /* no parameters */
#define IOC_OUT 0x40000000 /* copy out parameters */
#define IOC_IN 0x80000000 /* copy in parameters */
#define IOC_INOUT (IOC_IN | IOC_OUT)
#define IOC_DIRMASK (IOC_VOID | IOC_OUT | IOC_IN)
#define _IOC(inout, group, num, len) \
((unsigned long)((inout) | (((len) & IOCPARM_MASK) << 16) | ((group) << 8) | \
(num)))
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
#define _IOWINT(g, n) _IOC(IOC_VOID, (g), (n), sizeof(int))
#define _IOR(g, n, t) _IOC(IOC_OUT, (g), (n), sizeof(t))
#define _IOW(g, n, t) _IOC(IOC_IN, (g), (n), sizeof(t))
/* this should be _IORW, but stdio got there first */
#define _IOWR(g, n, t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
// clang-format on
static std::string iocGroupToString(unsigned iocGroup) {
if (iocGroup >= 128) {
const char *sceGroups[] = {
"DEV",
"DMEM",
"GC",
"DCE",
"UVD",
"VCE",
"DBGGC",
"TWSI",
"MDBG",
"DEVENV",
"AJM",
"TRACE",
"IBS",
"MBUS",
"HDMI",
"CAMERA",
"FAN",
"THERMAL",
"PFS",
"ICC_CONFIG",
"IPC",
"IOSCHED",
"ICC_INDICATOR",
"EXFATFS",
"ICC_NVS",
"DVE",
"ICC_POWER",
"AV_CONTROL",
"ICC_SC_CONFIGURATION",
"ICC_DEVICE_POWER",
"SSHOT",
"DCE_SCANIN",
"FSCTRL",
"HMD",
"SHM",
"PHYSHM",
"HMDDFU",
"BLUETOOTH_HID",
"SBI",
"S3DA",
"SPM",
"BLOCKPOOL",
"SDK_EVENTLOG",
};
if (iocGroup - 127 >= std::size(sceGroups)) {
return "'?'";
}
return sceGroups[iocGroup - 127];
}
if (isprint(iocGroup)) {
return "'" + std::string(1, (char)iocGroup) + "'";
}
return "'?'";
}
static void printIoctl(unsigned long arg) {
std::printf("0x%lx { IO%s%s %lu(%s), %lu, %lu }\n", arg,
arg & IOC_OUT ? "R" : "", arg & IOC_IN ? "W" : "", IOCGROUP(arg),
iocGroupToString(IOCGROUP(arg)).c_str(), arg & 0xFF,
IOCPARM_LEN(arg));
}
static void ioctlToStream(std::ostream &stream, unsigned long arg) {
stream << "0x" << std::hex << arg << " { IO";
if ((arg & IOC_OUT) != 0) {
stream << 'R';
}
if ((arg & IOC_IN) != 0) {
stream << 'W';
}
if ((arg & IOC_VOID) != 0) {
stream << 'i';
}
stream << " 0x" << IOCGROUP(arg);
stream << "('" << iocGroupToString(IOCGROUP(arg)) << "'), ";
stream << std::dec << (arg & 0xFF) << ", " << IOCPARM_LEN(arg) << " }";
}
static std::string ioctlToString(unsigned long arg) {
std::ostringstream stream;
ioctlToStream(stream, arg);
return std::move(stream).str();
}
orbis::SysResult orbis::sys_ioctl(Thread *thread, sint fd, ulong com,
caddr_t data) {
auto str = ioctlToString(com);
// ORBIS_LOG_WARNING(__FUNCTION__, fd, com, str);
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto ioctl = file->ops->ioctl;
if (ioctl == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
return ioctl(file.get(), com, data, thread);
}
orbis::SysResult orbis::sys_pselect(Thread *thread, sint nd, ptr<fd_set> in,
ptr<fd_set> ou, ptr<fd_set> ex,
ptr<const timespec> ts,
ptr<const sigset_t> sm) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_select(Thread *thread, sint nd,
ptr<struct fd_set_t> in,
ptr<struct fd_set_t> out,
ptr<struct fd_set_t> ex,
ptr<struct timeval> tv) {
if (tv == nullptr) {
orbis::scoped_unblock_now unblock;
std::this_thread::sleep_for(std::chrono::days(1));
} else {
std::this_thread::sleep_for(std::chrono::seconds(tv->tv_sec));
return orbis::ErrorCode::TIMEDOUT;
}
return {};
}
orbis::SysResult orbis::sys_poll(Thread *thread, ptr<struct pollfd> fds,
uint nfds, sint timeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_openbsd_poll(Thread *thread, ptr<struct pollfd> fds,
uint nfds, sint timeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_nlm_syscall(Thread *thread, sint debug_level,
sint grace_period, sint addr_count,
ptr<ptr<char>> addrs) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_nfssvc(Thread *thread, sint flag, caddr_t argp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sysarch(Thread *thread, sint op, ptr<char> parms) {
if (op == 129) {
uint64_t fs;
if (auto error = uread(fs, (ptr<uint64_t>)parms); error != ErrorCode{})
return error;
ORBIS_LOG_WARNING("sys_sysarch: set FS", (std::size_t)fs);
thread->fsBase = fs;
return {};
}
ORBIS_LOG_WARNING(__FUNCTION__, op, parms);
return {};
}
orbis::SysResult orbis::sys_nnpfs_syscall(Thread *thread, sint operation,
ptr<char> a_pathP, sint opcode,
ptr<void> a_paramsP,
sint a_followSymlinks) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_afs3_syscall(Thread *thread, slong syscall,
slong param1, slong param2,
slong param3, slong param4,
slong param5, slong param6) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_gssd_syscall(Thread *thread, ptr<char> path) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,19 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_jail(Thread *thread, ptr<struct jail> jail) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_jail_set(Thread *thread, ptr<IoVec> iovp,
uint iovcnt, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_jail_get(Thread *thread, ptr<IoVec> iovp,
uint iovcnt, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_jail_remove(Thread *thread, sint jid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_jail_attach(Thread *thread, sint jid) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,10 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_ktrace(Thread *thread, ptr<const char> fname,
sint ops, sint facs, sint pit) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_utrace(Thread *thread, ptr<const void> addr,
size_t len) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,29 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_kldload(Thread *thread, ptr<const char> file) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldunload(Thread *thread, sint fileid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldunloadf(Thread *thread, slong fileid,
sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldfind(Thread *thread, ptr<const char> name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldnext(Thread *thread, sint fileid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldstat(Thread *thread, sint fileid,
ptr<struct kld_file_stat> stat) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldfirstmod(Thread *thread, sint fileid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kldsym(Thread *thread, sint fileid, sint cmd,
ptr<void> data) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,9 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_getloginclass(Thread *thread, ptr<char> namebuf,
size_t namelen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setloginclass(Thread *thread, ptr<char> namebuf) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,44 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys___mac_get_pid(Thread *thread, pid_t pid,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_get_proc(Thread *thread,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_set_proc(Thread *thread,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_get_fd(Thread *thread, sint fd,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_get_file(Thread *thread, ptr<const char> path,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_set_fd(Thread *thread, sint fd,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_set_file(Thread *thread, ptr<const char> path,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_get_link(Thread *thread,
ptr<const char> path_p,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___mac_set_link(Thread *thread,
ptr<const char> path_p,
ptr<struct mac> mac_p) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mac_syscall(Thread *thread, ptr<const char> policy,
sint call, ptr<void> arg) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,15 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_modnext(Thread *thread, sint modid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_modfnext(Thread *thread, sint modid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_modstat(Thread *thread, sint modid,
ptr<struct module_stat> stat) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_modfind(Thread *thread, ptr<const char> name) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,22 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_msgctl(Thread *thread, sint msqid, sint cmd,
ptr<struct msqid_ds> buf) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_msgget(Thread *thread, key_t key, sint msgflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_msgsnd(Thread *thread, sint msqid,
ptr<const void> msgp, size_t msgsz,
sint msgflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_msgrcv(Thread *thread, sint msqid, ptr<void> msgp,
size_t msgsz, slong msgtyp, sint msgflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_msgsys(Thread *thread, sint which, sint a2, sint a3,
sint a4, sint a5, sint a6) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,13 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_ntp_gettime(Thread *thread,
ptr<struct ntptimeval> ntvp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ntp_adjtime(Thread *thread, ptr<struct timex> tp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_adjtime(Thread *thread, ptr<struct timeval> delta,
ptr<struct timeval> olddelta) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,42 @@
#include "sys/sysproto.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <thread>
orbis::SysResult
orbis::sys_sched_setparam(Thread *thread, pid_t pid,
ptr<const struct sched_param> param) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sched_getparam(Thread *thread, pid_t pid,
ptr<struct sched_param> param) {
return ErrorCode::NOSYS;
}
orbis::SysResult
orbis::sys_sched_setscheduler(Thread *thread, pid_t pid, sint policy,
ptr<const struct sched_param> param) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sched_getscheduler(Thread *thread, pid_t pid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sched_yield(Thread *thread) {
std::this_thread::yield();
return {};
}
orbis::SysResult orbis::sys_sched_get_priority_max(Thread *thread,
sint policy) {
ORBIS_LOG_ERROR(__FUNCTION__, policy);
thread->retval[0] = 90;
return {};
}
orbis::SysResult orbis::sys_sched_get_priority_min(Thread *thread,
sint policy) {
ORBIS_LOG_ERROR(__FUNCTION__, policy);
thread->retval[0] = 10;
return {};
}
orbis::SysResult orbis::sys_sched_rr_get_interval(Thread *thread, pid_t pid,
ptr<timespec> interval) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,15 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <pipe.hpp>
orbis::SysResult orbis::sys_pipe(Thread *thread) {
auto [a, b] = createPipe();
auto fd0 = thread->tproc->fileDescriptors.insert(a);
auto fd1 = thread->tproc->fileDescriptors.insert(b);
ORBIS_LOG_ERROR(__FUNCTION__, fd0, fd1);
thread->retval[0] = fd0;
thread->retval[1] = fd1;
return {};
}

View file

@ -0,0 +1,5 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_pdgetpid(Thread *thread, sint fd, ptr<pid_t> pidp) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,6 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_ptrace(Thread *thread, sint req, pid_t pid,
caddr_t addr, sint data) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,90 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
orbis::SysResult orbis::sys_getpid(Thread *thread) {
thread->retval[0] = thread->tproc->pid;
return {};
}
orbis::SysResult orbis::sys_getppid(Thread *thread) {
thread->retval[0] = thread->tproc->parentProcess
? thread->tproc->parentProcess->pid
: thread->tproc->pid;
return {};
}
orbis::SysResult orbis::sys_getpgrp(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_getpgid(Thread *thread, pid_t pid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getsid(Thread *thread, pid_t pid) { return {}; }
orbis::SysResult orbis::sys_getuid(Thread *thread) {
thread->retval[0] = 1;
return {};
}
orbis::SysResult orbis::sys_geteuid(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_getgid(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_getegid(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_getgroups(Thread *thread, uint gidsetsize,
ptr<gid_t> gidset) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setsid(Thread *thread) {
ORBIS_LOG_WARNING(__FUNCTION__);
return {};
}
orbis::SysResult orbis::sys_setpgid(Thread *thread, sint pid, sint pgid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setuid(Thread *thread, uid_t uid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_seteuid(Thread *thread, uid_t euid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setgid(Thread *thread, gid_t gid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setegid(Thread *thread, gid_t egid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setgroups(Thread *thread, uint gidsetsize,
ptr<gid_t> gidset) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setreuid(Thread *thread, sint ruid, sint euid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setregid(Thread *thread, sint rgid, sint egid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setresuid(Thread *thread, uid_t ruid, uid_t euid,
uid_t suid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setresgid(Thread *thread, gid_t rgid, gid_t egid,
gid_t sgid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getresuid(Thread *thread, ptr<uid_t> ruid,
ptr<uid_t> euid, ptr<uid_t> suid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getresgid(Thread *thread, ptr<gid_t> rgid,
ptr<gid_t> egid, ptr<gid_t> sgid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_issetugid(Thread *thread) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___setugid(Thread *thread, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getlogin(Thread *thread, ptr<char> namebuf,
uint namelen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setlogin(Thread *thread, ptr<char> namebuf) {
ORBIS_LOG_WARNING(__FUNCTION__, namebuf);
return {};
}

View file

@ -0,0 +1,5 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_posix_openpt(Thread *thread, sint flags) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,32 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_rctl_get_racct(Thread *thread,
ptr<const void> inbufp,
size_t inbuflen, ptr<void> outbuf,
size_t outbuflen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_rctl_get_rules(Thread *thread,
ptr<const void> inbufp,
size_t inbuflen, ptr<void> outbuf,
size_t outbuflen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_rctl_get_limits(Thread *thread,
ptr<const void> inbufp,
size_t inbuflen, ptr<void> outbuf,
size_t outbuflen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_rctl_add_rule(Thread *thread,
ptr<const void> inbufp,
size_t inbuflen, ptr<void> outbuf,
size_t outbuflen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_rctl_remove_rule(Thread *thread,
ptr<const void> inbufp,
size_t inbuflen, ptr<void> outbuf,
size_t outbuflen) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,140 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <sched.h>
namespace orbis {
struct rlimit {
int64_t softLimit;
int64_t hardLimit;
};
} // namespace orbis
orbis::SysResult orbis::sys_getpriority(Thread *thread, sint which, sint who) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setpriority(Thread *thread, sint which, sint who,
sint prio) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_rtprio_thread(Thread *thread, sint function,
lwpid_t lwpid,
ptr<struct rtprio> rtp) {
ORBIS_LOG_ERROR(__FUNCTION__, function, lwpid, rtp->prio, rtp->type);
thread->where();
Thread *targetThread;
if (lwpid == thread->tid || lwpid == -1) {
targetThread = thread;
} else {
targetThread = thread->tproc->threadsMap.get(lwpid - thread->tproc->pid);
if (targetThread == nullptr) {
return ErrorCode::SRCH;
}
}
if (function == 0) {
return orbis::uwrite(rtp, targetThread->prio);
} else if (function == 1) {
ORBIS_RET_ON_ERROR(orbis::uread(targetThread->prio, rtp));
int hostPolicy = SCHED_RR;
auto prioMin = sched_get_priority_min(hostPolicy);
auto prioMax = sched_get_priority_max(hostPolicy);
auto hostPriority =
(targetThread->prio.prio * (prioMax - prioMin + 1)) / 1000 - prioMin;
::sched_param hostParam{};
hostParam.sched_priority = hostPriority;
if (pthread_setschedparam(targetThread->getNativeHandle(), hostPolicy,
&hostParam)) {
auto normPrio = targetThread->prio.prio / 1000.f;
hostParam.sched_priority = 0;
if (normPrio < 0.3f) {
hostPolicy = SCHED_BATCH;
} else if (normPrio < 0.7f) {
hostPolicy = SCHED_OTHER;
} else {
hostPolicy = SCHED_IDLE;
}
if (pthread_setschedparam(targetThread->getNativeHandle(), hostPolicy,
&hostParam)) {
ORBIS_LOG_ERROR(
__FUNCTION__, "failed to set host priority", hostPriority,
targetThread->prio.prio, targetThread->prio.type, errno,
targetThread->getNativeHandle(), prioMin, prioMax, errno);
}
} else {
ORBIS_LOG_ERROR(__FUNCTION__, "set host priority", hostPriority,
targetThread->tid, targetThread->prio.prio,
targetThread->prio.type, prioMin, prioMax);
}
}
return {};
}
orbis::SysResult orbis::sys_rtprio(Thread *thread, sint function, pid_t pid,
ptr<struct rtprio> rtp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setrlimit(Thread *thread, uint which,
ptr<struct rlimit> rlp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getrlimit(Thread *thread, uint which,
ptr<struct rlimit> rlp) {
switch (which) {
case 0: { // cpu
break;
}
case 1: { // fsize
break;
}
case 2: { // data
break;
}
case 3: { // stack
break;
}
case 4: { // core
break;
}
case 5: { // rss
break;
}
case 6: { // memlock
break;
}
case 7: { // nproc
break;
}
case 8: { // nofile
break;
}
case 9: { // sbsize
break;
}
case 10: { // vmem
break;
}
case 11: { // npts
break;
}
case 12: { // swap
break;
}
default:
return ErrorCode::INVAL;
}
rlp->softLimit = 4096;
rlp->hardLimit = 4096;
return {};
}
orbis::SysResult orbis::sys_getrusage(Thread *thread, sint who,
ptr<struct rusage> rusage) {
return {};
}

View file

@ -0,0 +1,5 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_setfib(Thread *thread, sint fib) {
return ErrorCode::NOSYS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys___semctl(Thread *thread, sint semid, sint semnum,
sint cmd, ptr<union semun> arg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_semget(Thread *thread, key_t key, sint nsems,
sint semflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_semop(Thread *thread, sint semid,
ptr<struct sembuf> sops, size_t nspos) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_semsys(Thread *thread, sint which, sint a2, sint a3,
sint a4, sint a5) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,21 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_shmdt(Thread *thread, ptr<const void> shmaddr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_shmat(Thread *thread, sint shmid,
ptr<const void> shmaddr, sint shmflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_shmctl(Thread *thread, sint shmid, sint cmd,
ptr<struct shmid_ds> buf) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_shmget(Thread *thread, key_t key, size_t size,
sint shmflg) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_shmsys(Thread *thread, sint which, sint a2, sint a3,
sint a4) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,5 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_reboot(Thread *thread, sint opt) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,153 @@
#include "KernelContext.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
#include "ucontext.hpp"
#include "utils/Logs.hpp"
#include <csignal>
orbis::SysResult orbis::sys_sigaction(Thread *thread, sint sig,
ptr<SigAction> act, ptr<SigAction> oact) {
ORBIS_LOG_WARNING(__FUNCTION__, sig, act, oact);
auto &sigAct = thread->tproc->sigActions[sig];
if (oact != nullptr) {
if (auto errc = uwrite(oact, sigAct); errc != orbis::ErrorCode{}) {
return errc;
}
}
if (act != nullptr) {
if (auto errc = uread(sigAct, act); errc != ErrorCode{}) {
return errc;
}
ORBIS_LOG_WARNING(__FUNCTION__, sigAct.handler, sigAct.flags,
sigAct.mask.bits[0], sigAct.mask.bits[1],
sigAct.mask.bits[2], sigAct.mask.bits[3]);
}
return {};
}
orbis::SysResult orbis::sys_sigprocmask(Thread *thread, sint how,
ptr<SigSet> set, ptr<SigSet> oset) {
std::lock_guard lock(thread->mtx);
if (oset) {
ORBIS_RET_ON_ERROR(uwrite(oset, thread->sigMask));
}
if (set) {
SigSet _set;
ORBIS_RET_ON_ERROR(uread(_set, set));
auto newSigMask = thread->sigMask;
auto oldSigMask = newSigMask;
switch (how) {
case 1: // block
for (std::size_t i = 0; i < 4; ++i) {
newSigMask.bits[i] |= _set.bits[i];
}
break;
case 2: // unblock
for (std::size_t i = 0; i < 4; ++i) {
newSigMask.bits[i] &= ~_set.bits[i];
}
break;
case 3: // set
newSigMask = _set;
break;
default:
ORBIS_LOG_ERROR("sys_sigprocmask: unimplemented how", how);
thread->where();
return ErrorCode::INVAL;
}
newSigMask.clear(kSigKill);
newSigMask.clear(kSigStop);
thread->sigMask = newSigMask;
for (std::size_t word = 0; word < std::size(newSigMask.bits); ++word) {
auto unblockedBits = ~oldSigMask.bits[word] & newSigMask.bits[word];
std::uint32_t offset = word * 32 + 1;
for (std::uint32_t i = std::countr_zero(unblockedBits); i < 32;
i += std::countr_zero(unblockedBits >> (i + 1)) + 1) {
thread->notifyUnblockedSignal(offset + i);
}
}
}
return {};
}
orbis::SysResult orbis::sys_sigwait(Thread *thread, ptr<const SigSet> set,
ptr<sint> sig) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigtimedwait(Thread *thread, ptr<const SigSet> set,
ptr<struct siginfo> info,
ptr<const timespec> timeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigwaitinfo(Thread *thread, ptr<const SigSet> set,
ptr<struct siginfo> info) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigpending(Thread *thread, ptr<SigSet> set) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigsuspend(Thread *thread, ptr<const SigSet> set) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigaltstack(Thread *thread, ptr<struct stack_t> ss,
ptr<struct stack_t> oss) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kill(Thread *thread, sint pid, sint signum) {
ORBIS_LOG_WARNING(__FUNCTION__, pid, signum);
int hostPid = pid;
if (pid > 0) {
auto process = g_context.findProcessById(pid);
if (process == nullptr) {
return ErrorCode::SRCH;
}
hostPid = process->hostPid;
}
// FIXME: invoke subscriber thread
int result = ::sigqueue(hostPid, SIGUSR1, {.sival_int = signum});
if (result < 0) {
return static_cast<ErrorCode>(errno);
}
return {};
}
orbis::SysResult orbis::sys_pdkill(Thread *thread, sint fd, sint signum) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigqueue(Thread *thread, pid_t pid, sint signum,
ptr<void> value) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sigreturn(Thread *thread, ptr<UContext> sigcntxp) {
ORBIS_LOG_WARNING(__FUNCTION__, sigcntxp);
if (auto sigreturn = thread->tproc->ops->sigreturn) {
return sigreturn(thread, sigcntxp);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::nosys(Thread *thread) {
thread->sendSignal(kSigSys);
return {};
}

View file

@ -0,0 +1,6 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_profil(Thread *thread, caddr_t samples, size_t size,
size_t offset, uint scale) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,8 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_swapon(Thread *thread, ptr<char> name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_swapoff(Thread *thread, ptr<const char> name) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,7 @@
#include "sys/sysproto.hpp"
#include <thread>
orbis::SysResult orbis::sys_yield(Thread *thread) {
std::this_thread::yield();
return {};
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,77 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
#include "ucontext.hpp"
orbis::SysResult orbis::sys_thr_create(Thread *thread, ptr<UContext> ctxt,
ptr<slong> arg, sint flags) {
if (auto thr_create = thread->tproc->ops->thr_create) {
return thr_create(thread, ctxt, arg, flags);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_new(Thread *thread, ptr<struct thr_param> param,
sint param_size) {
if (auto thr_new = thread->tproc->ops->thr_new) {
return thr_new(thread, param, param_size);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_self(Thread *thread, ptr<slong> id) {
return uwrite(id, (slong)thread->tid);
}
orbis::SysResult orbis::sys_thr_exit(Thread *thread, ptr<slong> state) {
if (auto thr_exit = thread->tproc->ops->thr_exit) {
return thr_exit(thread, state);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_kill(Thread *thread, slong id, sint sig) {
if (auto thr_kill = thread->tproc->ops->thr_kill) {
return thr_kill(thread, id, sig);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_kill2(Thread *thread, pid_t pid, slong id,
sint sig) {
if (auto thr_kill2 = thread->tproc->ops->thr_kill2) {
return thr_kill2(thread, pid, id, sig);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_suspend(Thread *thread,
ptr<const timespec> timeout) {
if (auto thr_suspend = thread->tproc->ops->thr_suspend) {
return thr_suspend(thread, timeout);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_wake(Thread *thread, slong id) {
if (auto thr_wake = thread->tproc->ops->thr_wake) {
return thr_wake(thread, id);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_thr_set_name(Thread *thread, slong id,
ptr<const char> name) {
if (auto thr_set_name = thread->tproc->ops->thr_set_name) {
return thr_set_name(thread, id, name);
}
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,199 @@
#include "sys/sysproto.hpp"
#include "time.hpp"
#include "utils/Logs.hpp"
#include <sys/time.h>
enum class ClockId {
Realtime = 0,
Virtual = 1,
Prof = 2,
Monotonic = 4,
Uptime = 5, // FreeBSD-specific
UptimePrecise = 7, // FreeBSD-specific
UptimeFast = 8, // FreeBSD-specific
RealtimePrecise = 9, // FreeBSD-specific
RealtimeFast = 10, // FreeBSD-specific
MonotonicPrecise = 11, // FreeBSD-specific
MonotonicFast = 12, // FreeBSD-specific
Second = 13, // FreeBSD-specific
ThreadCputimeId = 14,
// orbis extension
Proctime = 15,
Network = 16,
DebugNetwork = 17,
AdNetwork = 18,
RawNetwork = 19,
};
orbis::SysResult orbis::sys_clock_gettime(Thread *, clockid_t clock_id,
ptr<timespec> tp) {
timespec result{};
auto getHostClock = [](clockid_t clock_id) {
::timespec hostClock;
::clock_gettime(clock_id, &hostClock);
timespec result;
result.sec = hostClock.tv_sec;
result.nsec = hostClock.tv_nsec;
return result;
};
switch (static_cast<ClockId>(clock_id)) {
case ClockId::Realtime:
case ClockId::RealtimePrecise:
result = getHostClock(CLOCK_REALTIME);
break;
case ClockId::RealtimeFast: {
result = getHostClock(CLOCK_REALTIME); // FIXME
break;
}
case ClockId::Virtual:
ORBIS_LOG_ERROR("Unimplemented ClockId::Virtual\n");
break;
case ClockId::Prof:
ORBIS_LOG_ERROR("Unimplemented ClockId::Prof\n");
break;
case ClockId::Monotonic:
case ClockId::MonotonicPrecise:
case ClockId::Uptime:
case ClockId::UptimePrecise: {
result = getHostClock(CLOCK_MONOTONIC);
break;
}
case ClockId::UptimeFast:
case ClockId::MonotonicFast:
result = getHostClock(CLOCK_MONOTONIC); // FIXME
break;
case ClockId::Second: {
result = getHostClock(CLOCK_MONOTONIC); // FIXME
result.nsec = 0;
break;
}
case ClockId::ThreadCputimeId:
result = getHostClock(CLOCK_THREAD_CPUTIME_ID);
break;
case ClockId::Proctime:
result = getHostClock(CLOCK_PROCESS_CPUTIME_ID);
break;
case ClockId::Network:
// TODO
// ORBIS_LOG_ERROR("Unimplemented ClockId::Network");
result = getHostClock(CLOCK_PROCESS_CPUTIME_ID);
break;
case ClockId::DebugNetwork:
// TODO
// ORBIS_LOG_ERROR("Unimplemented ClockId::DebugNetwork");
result = getHostClock(CLOCK_PROCESS_CPUTIME_ID);
break;
case ClockId::AdNetwork:
// TODO
// ORBIS_LOG_ERROR("Unimplemented ClockId::AdNetwork");
result = getHostClock(CLOCK_PROCESS_CPUTIME_ID);
break;
case ClockId::RawNetwork:
// TODO
// ORBIS_LOG_ERROR("Unimplemented ClockId::RawNetwork");
result = getHostClock(CLOCK_PROCESS_CPUTIME_ID);
break;
default:
return ErrorCode::INVAL;
}
return uwrite(tp, result);
}
orbis::SysResult orbis::sys_clock_settime(Thread *thread, clockid_t clock_id,
ptr<const timespec> tp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_clock_getres(Thread *thread, clockid_t clock_id,
ptr<timespec> tp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_nanosleep(Thread *thread,
cptr<orbis::timespec> rqtp,
ptr<orbis::timespec> rmtp) {
ORBIS_LOG_TRACE(__FUNCTION__, rqtp, rmtp);
struct ::timespec rq;
struct ::timespec rm;
orbis::timespec value;
if (auto e = uread(value, rqtp); e != ErrorCode{})
return e;
rq.tv_sec = value.sec;
rq.tv_nsec = value.nsec;
if (::nanosleep(&rq, &rm) == EINTR) {
if (rmtp) {
value.sec = rm.tv_sec;
value.nsec = rm.tv_nsec;
if (auto e = uwrite(rmtp, value); e != ErrorCode{})
return e;
}
return ErrorCode::INTR;
}
return {};
}
orbis::SysResult orbis::sys_gettimeofday(Thread *thread, ptr<orbis::timeval> tp,
ptr<orbis::timezone> tzp) {
ORBIS_LOG_TRACE(__FUNCTION__, tp, tzp);
struct ::timeval tv;
if (::gettimeofday(&tv, nullptr) != 0)
std::abort();
if (tp) {
orbis::timeval value;
value.tv_sec = tv.tv_sec;
value.tv_usec = tv.tv_usec;
if (auto e = uwrite(tp, value); e != ErrorCode{})
return e;
}
if (tzp) {
struct ::tm tp;
if (localtime_r(&tv.tv_sec, &tp) != &tp)
std::abort();
orbis::timezone value;
value.tz_dsttime = 0; // TODO
value.tz_mineast = tp.tm_gmtoff / 60;
if (auto e = uwrite(tzp, value); e != ErrorCode{})
return e;
}
return {};
}
orbis::SysResult orbis::sys_settimeofday(Thread *thread, ptr<struct timeval> tp,
ptr<orbis::timezone> tzp) {
return {};
}
orbis::SysResult orbis::sys_getitimer(Thread *thread, uint which,
ptr<struct itimerval> itv) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_setitimer(Thread *thread, uint which,
ptr<struct itimerval> itv,
ptr<struct itimerval> oitv) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ktimer_create(Thread *thread, clockid_t clock_id,
ptr<struct sigevent> evp,
ptr<sint> timerid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ktimer_delete(Thread *thread, sint timerid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ktimer_settime(Thread *thread, sint timerid,
sint flags,
ptr<const struct itimerspec> value,
ptr<struct itimerspec> ovalue) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ktimer_gettime(Thread *thread, sint timerid,
ptr<struct itimerspec> value) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ktimer_getoverrun(Thread *thread, sint timerid) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,229 @@
#include "file.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
#include "uio.hpp"
#include "utils/Logs.hpp"
#include <sys/socket.h>
orbis::SysResult orbis::sys_socket(Thread *thread, sint domain, sint type,
sint protocol) {
ORBIS_LOG_TODO(__FUNCTION__, domain, type, protocol);
if (auto socket = thread->tproc->ops->socket) {
Ref<File> file;
auto result = socket(thread, nullptr, domain, type, protocol, &file);
if (result.isError()) {
return result;
}
auto fd = thread->tproc->fileDescriptors.insert(file);
ORBIS_LOG_WARNING("Socket opened", fd);
thread->retval[0] = fd;
return {};
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_bind(Thread *thread, sint s, caddr_t name,
sint namelen) {
// ORBIS_LOG_ERROR(__FUNCTION__, s, name, namelen);
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto bind = file->ops->bind) {
return bind(file.get(), ptr<SocketAddress>(name), namelen, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_listen(Thread *thread, sint s, sint backlog) {
ORBIS_LOG_ERROR(__FUNCTION__, s, backlog);
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto listen = file->ops->listen) {
return listen(file.get(), backlog, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_accept(Thread *thread, sint s,
ptr<SocketAddress> from,
ptr<uint32_t> fromlenaddr) {
ORBIS_LOG_ERROR(__FUNCTION__, s, from, fromlenaddr);
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto accept = file->ops->accept) {
return accept(file.get(), from, fromlenaddr, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_connect(Thread *thread, sint s, caddr_t name,
sint namelen) {
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto connect = file->ops->connect) {
return connect(file.get(), ptr<SocketAddress>(name), namelen, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_socketpair(Thread *thread, sint domain, sint type,
sint protocol, ptr<sint> rsv) {
ORBIS_LOG_TODO(__FUNCTION__, domain, type, protocol, rsv);
if (auto socketpair = thread->tproc->ops->socketpair) {
Ref<File> a;
Ref<File> b;
auto result = socketpair(thread, domain, type, protocol, &a, &b);
if (result.isError()) {
return result;
}
auto aFd = thread->tproc->fileDescriptors.insert(a);
auto bFd = thread->tproc->fileDescriptors.insert(b);
if (auto errc = uwrite(rsv, aFd); errc != ErrorCode{}) {
return errc;
}
return uwrite(rsv + 1, bFd);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sendto(Thread *thread, sint s, caddr_t buf,
size_t len, sint flags, caddr_t to,
sint tolen) {
return {};
}
orbis::SysResult orbis::sys_sendmsg(Thread *thread, sint s,
ptr<struct msghdr> msg, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_recvfrom(Thread *thread, sint s, caddr_t buf,
size_t len, sint flags,
ptr<SocketAddress> from,
ptr<uint32_t> fromlenaddr) {
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto recvfrom = file->ops->recvfrom) {
return SysResult::notAnError(
recvfrom(file.get(), buf, len, flags, from, fromlenaddr, thread));
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_recvmsg(Thread *thread, sint s,
ptr<struct msghdr> msg, sint flags) {
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto recvmsg = file->ops->recvmsg) {
return recvmsg(file.get(), msg, flags, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_shutdown(Thread *thread, sint s, sint how) {
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto shutdown = file->ops->shutdown) {
return shutdown(file.get(), how, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_setsockopt(Thread *thread, sint s, sint level,
sint name, caddr_t val, sint valsize) {
ORBIS_LOG_TODO(__FUNCTION__, s, level, name, val, valsize);
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto setsockopt = file->ops->setsockopt) {
return setsockopt(file.get(), level, name, val, valsize, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_getsockopt(Thread *thread, sint s, sint level,
sint name, caddr_t val,
ptr<sint> avalsize) {
ORBIS_LOG_TODO(__FUNCTION__, s, level, name, val, avalsize);
auto file = thread->tproc->fileDescriptors.get(s);
if (file == nullptr) {
return ErrorCode::BADF;
}
if (auto getsockopt = file->ops->getsockopt) {
return getsockopt(file.get(), level, name, val, avalsize, thread);
}
return ErrorCode::NOTSUP;
}
orbis::SysResult orbis::sys_getsockname(Thread *thread, sint fdes,
ptr<SocketAddress> asa,
ptr<uint32_t> alen) {
// return uwrite<uint32_t>(alen, sizeof(SockAddr));
ORBIS_LOG_TODO(__FUNCTION__);
return {};
}
orbis::SysResult orbis::sys_getpeername(Thread *thread, sint fdes,
ptr<SocketAddress> asa,
ptr<uint32_t> alen) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sendfile(Thread *thread, sint fd, sint s,
off_t offset, size_t nbytes,
ptr<struct sf_hdtr> hdtr,
ptr<off_t> sbytes, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sctp_peeloff(Thread *thread, sint sd,
uint32_t name) {
return ErrorCode::NOSYS;
}
orbis::SysResult
orbis::sys_sctp_generic_sendmsg(Thread *thread, sint sd, caddr_t msg, sint mlen,
caddr_t to, __socklen_t tolen,
ptr<struct sctp_sndrcvinfo> sinfo, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_sctp_generic_sendmsg_iov(
Thread *thread, sint sd, ptr<IoVec> iov, sint iovlen, caddr_t to,
__socklen_t tolen, ptr<struct sctp_sndrcvinfo> sinfo, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult
orbis::sys_sctp_generic_recvmsg(Thread *thread, sint sd, ptr<IoVec> iov,
sint iovlen, caddr_t from, __socklen_t fromlen,
ptr<struct sctp_sndrcvinfo> sinfo, sint flags) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,31 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_kmq_open(Thread *thread, ptr<const char> path,
sint flags, mode_t mode,
ptr<const struct mq_attr> attr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kmq_unlink(Thread *thread, ptr<const char> path) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kmq_setattr(Thread *thread, sint mqd,
ptr<const struct mq_attr> attr,
ptr<struct mq_attr> oattr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kmq_timedreceive(Thread *thread, sint mqd,
ptr<const char> msg_ptr,
size_t msg_len, ptr<uint> msg_prio,
ptr<const timespec> abstimeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kmq_timedsend(Thread *thread, sint mqd,
ptr<char> msg_ptr, size_t msg_len,
ptr<uint> msg_prio,
ptr<const timespec> abstimeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_kmq_notify(Thread *thread, sint mqd,
ptr<const struct sigevent> sigev) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,37 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_ksem_init(Thread *thread, ptr<semid_t> idp,
uint value) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_open(Thread *thread, ptr<semid_t> idp,
ptr<const char> name, sint oflag,
mode_t mode, uint value) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_unlink(Thread *thread, ptr<const char> name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_close(Thread *thread, semid_t id) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_post(Thread *thread, semid_t id) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_wait(Thread *thread, semid_t id) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_timedwait(Thread *thread, semid_t id,
ptr<const timespec> abstime) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_trywait(Thread *thread, semid_t id) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_getvalue(Thread *thread, semid_t id,
ptr<sint> value) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ksem_destroy(Thread *thread, semid_t id) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,45 @@
#include "file.hpp"
#include "orbis-config.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
orbis::SysResult orbis::sys_shm_open(Thread *thread, ptr<const char> path,
sint flags, mode_t mode) {
char _name[256];
if (auto result = ureadString(_name, sizeof(_name), path);
result != ErrorCode{}) {
return result;
}
if (auto shm_open = thread->tproc->ops->shm_open) {
Ref<File> file;
auto result = shm_open(thread, path, flags, mode, &file);
if (result.isError()) {
return result;
}
thread->retval[0] = thread->tproc->fileDescriptors.insert(file);
return {};
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_shm_unlink(Thread *thread, ptr<const char> path) {
char _name[256];
if (auto result = ureadString(_name, sizeof(_name), path);
result != ErrorCode{}) {
return result;
}
if (auto shm_unlink = thread->tproc->ops->shm_unlink) {
auto result = shm_unlink(thread, path);
if (result.isError()) {
return result;
}
return {};
}
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,177 @@
#include "orbis/utils/Logs.hpp"
#include "sys/sysproto.hpp"
#include "thread/Thread.hpp"
#include "time.hpp"
#include "umtx.hpp"
#include <chrono>
static orbis::ErrorCode ureadTimespec(orbis::timespec &ts,
orbis::ptr<orbis::timespec> addr) {
orbis::ErrorCode error = uread(ts, addr);
if (error != orbis::ErrorCode{})
return error;
if (ts.sec < 0 || ts.nsec < 0 || ts.nsec > 1000000000) {
return orbis::ErrorCode::INVAL;
}
return {};
}
orbis::SysResult orbis::sys__umtx_lock(Thread *thread, ptr<umtx> umtx) {
ORBIS_LOG_TRACE(__FUNCTION__, umtx);
if (reinterpret_cast<std::uintptr_t>(umtx) - 0x10000 > 0xff'fffe'ffff)
return ErrorCode::FAULT;
return umtx_lock_umtx(thread, umtx, thread->tid, -1);
}
orbis::SysResult orbis::sys__umtx_unlock(Thread *thread, ptr<umtx> umtx) {
ORBIS_LOG_TRACE(__FUNCTION__, umtx);
if (reinterpret_cast<std::uintptr_t>(umtx) - 0x10000 > 0xff'fffe'ffff)
return ErrorCode::FAULT;
return umtx_unlock_umtx(thread, umtx, thread->tid);
}
orbis::SysResult orbis::sys__umtx_op(Thread *thread, ptr<void> obj, sint op,
ulong val, ptr<void> uaddr1,
ptr<void> uaddr2) {
ORBIS_LOG_TRACE(__FUNCTION__, obj, op, val, uaddr1, uaddr2);
if (reinterpret_cast<std::uintptr_t>(obj) - 0x10000 > 0xff'fffe'ffff)
return ErrorCode::FAULT;
auto with_timeout = [&](auto op, bool loop = true) -> SysResult {
timespec *ts = nullptr;
timespec timeout{};
if (uaddr2 != nullptr) {
auto result = ureadTimespec(timeout, (ptr<timespec>)uaddr2);
if (result != ErrorCode{}) {
return result;
}
ts = &timeout;
}
if (!ts) {
if (!loop)
return op(-1);
while (true) {
if (auto r = op(-1); r != ErrorCode::TIMEDOUT)
return r;
}
} else {
__uint128_t usec = timeout.sec;
usec *= 1000'000;
usec += (timeout.nsec + 999) / 1000;
if (usec >= UINT64_MAX)
usec = -2;
if (!loop) {
if (auto result = op(usec); result != ErrorCode::TIMEDOUT) {
return result;
}
return SysResult::notAnError(ErrorCode::TIMEDOUT);
}
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
if (auto r = op(usec - udiff); r != ErrorCode::TIMEDOUT)
return r;
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= usec)
return SysResult::notAnError(ErrorCode::TIMEDOUT);
}
}
};
switch (op) {
case kUmtxOpLock: {
return with_timeout([&](std::uint64_t ut) {
return umtx_lock_umtx(thread, (ptr<umtx>)obj, val, ut);
});
}
case kUmtxOpUnlock:
return umtx_unlock_umtx(thread, (ptr<umtx>)obj, val);
case kUmtxOpWait: {
return with_timeout(
[&](std::uint64_t ut) {
return umtx_wait(thread, obj, val, ut, false, true);
},
false);
}
case kUmtxOpWake:
return umtx_wake(thread, obj, val);
case kUmtxOpMutexTrylock:
return umtx_trylock_umutex(thread, (ptr<umutex>)obj);
case kUmtxOpMutexLock: {
return with_timeout([&](std::uint64_t ut) {
return umtx_lock_umutex(thread, (ptr<umutex>)obj, ut);
});
}
case kUmtxOpMutexUnock:
return umtx_unlock_umutex(thread, (ptr<umutex>)obj);
case kUmtxOpSetCeiling:
return umtx_set_ceiling(thread, (ptr<umutex>)obj, val,
(ptr<uint32_t>)uaddr1);
case kUmtxOpCvWait: {
return with_timeout(
[&](std::uint64_t ut) {
return umtx_cv_wait(thread, (ptr<ucond>)obj, (ptr<umutex>)uaddr1, ut,
val);
},
false);
}
case kUmtxOpCvSignal:
return umtx_cv_signal(thread, (ptr<ucond>)obj);
case kUmtxOpCvBroadcast:
return umtx_cv_broadcast(thread, (ptr<ucond>)obj);
case kUmtxOpWaitUint: {
return with_timeout(
[&](std::uint64_t ut) {
return umtx_wait(thread, obj, val, ut, true, true);
},
false);
}
case kUmtxOpRwRdLock:
return with_timeout([&](std::uint64_t ut) {
return umtx_rw_rdlock(thread, (ptr<urwlock>)obj, val, ut);
});
case kUmtxOpRwWrLock:
return with_timeout([&](std::uint64_t ut) {
return umtx_rw_wrlock(thread, (ptr<urwlock>)obj, ut);
});
case kUmtxOpRwUnlock:
return umtx_rw_unlock(thread, (ptr<urwlock>)obj);
case kUmtxOpWaitUintPrivate: {
return with_timeout(
[&](std::uint64_t ut) {
return umtx_wait(thread, obj, val, ut, true, false);
},
false);
}
case kUmtxOpWakePrivate:
return umtx_wake_private(thread, obj, val);
case kUmtxOpMutexWait: {
return with_timeout([&](std::uint64_t ut) {
return umtx_wait_umutex(thread, (ptr<umutex>)obj, ut);
});
}
case kUmtxOpMutexWake:
return umtx_wake_umutex(thread, (ptr<umutex>)obj, 0);
case kUmtxOpSemWait:
return with_timeout(
[&](std::uint64_t ut) {
return umtx_sem_wait(thread, (ptr<usem>)obj, ut);
},
false);
case kUmtxOpSemWake:
return umtx_sem_wake(thread, (ptr<usem>)obj);
case kUmtxOpNwakePrivate:
return umtx_nwake_private(thread, (ptr<void *>)obj, val);
case kUmtxOpMutexWake2:
return umtx_wake2_umutex(thread, (orbis::ptr<orbis::umutex>)obj, val);
case kUmtxOpMutexWake3:
return umtx_wake3_umutex(thread, (orbis::ptr<orbis::umutex>)obj, val);
}
return ErrorCode::INVAL;
}

View file

@ -0,0 +1,6 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_uuidgen(Thread *thread, ptr<struct uuid> store,
sint count) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,498 @@
#include "stat.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
#include "utils/Logs.hpp"
#include <filesystem>
#include <span>
orbis::SysResult orbis::sys_sync(Thread *thread) { return ErrorCode::NOSYS; }
orbis::SysResult orbis::sys_quotactl(Thread *thread, ptr<char> path, sint cmd,
sint uid, caddr_t arg) {
return ErrorCode::NOSYS;
}
namespace orbis {
struct statfs {
char pad[0x118];
char f_fstypename[16]; /* filesystem type name */
char f_mntfromname[88]; /* mounted filesystem */
char f_mntonname[88]; /* directory on which mounted */
};
} // namespace orbis
orbis::SysResult orbis::sys_statfs(Thread *thread, ptr<char> path,
ptr<struct statfs> buf) {
if (buf == 0) {
thread->retval[0] = 1;
return {};
}
std::strncpy(buf->f_fstypename, "unionfs", sizeof(buf->f_fstypename));
std::strncpy(buf->f_mntfromname, "/dev/super-hdd",
sizeof(buf->f_mntfromname));
std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname));
thread->retval[0] = 1;
return {};
}
orbis::SysResult orbis::sys_fstatfs(Thread *thread, sint fd,
ptr<struct statfs> buf) {
if (buf == 0) {
thread->retval[0] = 1;
return {};
}
std::strncpy(buf->f_fstypename, "unionfs", sizeof(buf->f_fstypename));
std::strncpy(buf->f_mntfromname, "/dev/super-hdd",
sizeof(buf->f_mntfromname));
std::strncpy(buf->f_mntonname, "/system/", sizeof(buf->f_mntonname));
thread->retval[0] = 1;
return {};
}
orbis::SysResult orbis::sys_getfsstat(Thread *thread, ptr<struct statfs> buf,
slong bufsize, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fchdir(Thread *thread, sint fd) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_chdir(Thread *thread, ptr<char> path) {
ORBIS_LOG_WARNING(__FUNCTION__, path);
thread->tproc->cwd = std::filesystem::path(path).lexically_normal().string();
return {};
}
orbis::SysResult orbis::sys_chroot(Thread *thread, ptr<char> path) {
ORBIS_LOG_WARNING(__FUNCTION__, path);
thread->tproc->root = path;
return {};
}
// volatile bool debuggerPresent = false;
orbis::SysResult orbis::sys_open(Thread *thread, ptr<const char> path,
sint flags, sint mode) {
if (auto open = thread->tproc->ops->open) {
Ref<File> file;
auto result = open(thread, path, flags, mode, &file);
if (result.isError()) {
return result;
}
auto fd = thread->tproc->fileDescriptors.insert(file);
thread->retval[0] = fd;
// if (path ==
// std::string_view{"/app0/psm/Application/resource/Sce.Vsh.ShellUI.SystemMessage.rco"})
// {
ORBIS_LOG_SUCCESS(__FUNCTION__, thread->tid, path, flags, mode, fd);
if (path == std::string_view{"/app0/wave/wave1.fbxd"}) {
thread->where();
}
// while (debuggerPresent == false) {
// std::this_thread::sleep_for(std::chrono::seconds(1));
// }
// // thread->where();
// }
return {};
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_openat(Thread *thread, sint fd, ptr<char> path,
sint flag, mode_t mode) {
ORBIS_LOG_WARNING(__FUNCTION__, fd, path, flag, mode);
if (fd == -100) {
std::string cwd;
{
std::lock_guard lock(thread->tproc->mtx);
cwd = std::string(thread->tproc->cwd);
}
return sys_open(thread, (cwd + "/" + path).c_str(), flag, mode);
}
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mknod(Thread *thread, ptr<char> path, sint mode,
sint dev) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mknodat(Thread *thread, sint fd, ptr<char> path,
mode_t mode, dev_t dev) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mkfifo(Thread *thread, ptr<char> path, sint mode) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mkfifoat(Thread *thread, sint fd, ptr<char> path,
mode_t mode) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_link(Thread *thread, ptr<char> path,
ptr<char> link) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_linkat(Thread *thread, sint fd1, ptr<char> path1,
sint fd2, ptr<char> path2, sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_symlink(Thread *thread, ptr<char> path,
ptr<char> link) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_symlinkat(Thread *thread, ptr<char> path1, sint fd,
ptr<char> path2) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_undelete(Thread *thread, ptr<char> path) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_unlink(Thread *thread, ptr<char> path) {
if (auto unlink = thread->tproc->ops->unlink) {
return unlink(thread, path);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_unlinkat(Thread *thread, sint fd, ptr<char> path,
sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lseek(Thread *thread, sint fd, off_t offset,
sint whence) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
std::lock_guard lock(file->mtx);
// TODO: use ioctl?
switch (whence) {
case SEEK_SET:
file->nextOff = offset;
break;
case SEEK_CUR:
file->nextOff += offset;
break;
case SEEK_END: {
if (file->ops->stat == nullptr) {
ORBIS_LOG_ERROR("seek with end whence: unimplemented stat");
return ErrorCode::NOTSUP;
}
orbis::Stat stat;
auto result = file->ops->stat(file.get(), &stat, thread);
if (result != ErrorCode{}) {
return result;
}
file->nextOff = stat.size + offset;
break;
}
default:
ORBIS_LOG_ERROR("sys_lseek: unimplemented whence", whence);
return ErrorCode::NOSYS;
}
ORBIS_LOG_ERROR(__FUNCTION__, fd, offset, whence, file->nextOff);
thread->retval[0] = file->nextOff;
return {};
}
orbis::SysResult orbis::sys_freebsd6_lseek(Thread *thread, sint fd, sint,
off_t offset, sint whence) {
return sys_lseek(thread, fd, offset, whence);
}
orbis::SysResult orbis::sys_access(Thread *thread, ptr<char> path, sint flags) {
if (auto open = thread->tproc->ops->open) {
Ref<File> file;
return open(thread, path, flags, 0, &file);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_faccessat(Thread *thread, sint fd, ptr<char> path,
sint mode, sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_eaccess(Thread *thread, ptr<char> path,
sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_stat(Thread *thread, ptr<char> path, ptr<Stat> ub) {
ORBIS_LOG_WARNING(__FUNCTION__, path);
Ref<File> file;
auto result = thread->tproc->ops->open(thread, path, 0, 0, &file);
if (result.isError()) {
return result;
}
auto stat = file->ops->stat;
if (stat == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
Stat _ub;
result = uread(_ub, ub);
if (result.isError()) {
return result;
}
result = stat(file.get(), &_ub, thread);
if (result.isError()) {
return result;
}
return uwrite(ub, _ub);
}
orbis::SysResult orbis::sys_fstatat(Thread *thread, sint fd, ptr<char> path,
ptr<Stat> buf, sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lstat(Thread *thread, ptr<char> path,
ptr<Stat> ub) {
return sys_stat(thread, path, ub);
}
orbis::SysResult orbis::sys_nstat(Thread *thread, ptr<char> path,
ptr<struct nstat> ub) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_nlstat(Thread *thread, ptr<char> path,
ptr<struct nstat> ub) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_pathconf(Thread *thread, ptr<char> path,
sint name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lpathconf(Thread *thread, ptr<char> path,
sint name) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_readlink(Thread *thread, ptr<char> path,
ptr<char> buf, size_t count) {
char _path[1024];
ORBIS_RET_ON_ERROR(ureadString(_path, sizeof(_path), path));
auto pathLen = std::strlen(_path);
if (pathLen > count) {
return ErrorCode::NAMETOOLONG;
}
Ref<File> file;
if (auto error = thread->tproc->ops->open(thread, path, 0, 0, &file);
error.value()) {
return error;
}
ORBIS_RET_ON_ERROR(uwriteRaw(buf, _path, pathLen));
thread->retval[0] = pathLen;
return {};
}
orbis::SysResult orbis::sys_readlinkat(Thread *thread, sint fd, ptr<char> path,
ptr<char> buf, size_t bufsize) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_chflags(Thread *thread, ptr<char> path,
sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lchflags(Thread *thread, ptr<const char> path,
sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fchflags(Thread *thread, sint fd, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_chmod(Thread *thread, ptr<char> path, sint mode) {
return {};
}
orbis::SysResult orbis::sys_fchmodat(Thread *thread, sint fd, ptr<char> path,
mode_t mode, sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lchmod(Thread *thread, ptr<char> path,
mode_t mode) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fchmod(Thread *thread, sint fd, sint mode) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_chown(Thread *thread, ptr<char> path, sint uid,
sint gid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fchownat(Thread *thread, sint fd, ptr<char> path,
uid_t uid, gid_t gid, sint flag) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lchown(Thread *thread, ptr<char> path, sint uid,
sint gid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fchown(Thread *thread, sint fd, sint uid,
sint gid) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_utimes(Thread *thread, ptr<char> path,
ptr<struct timeval> tptr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_futimesat(Thread *thread, sint fd, ptr<char> path,
ptr<struct timeval> times) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lutimes(Thread *thread, ptr<char> path,
ptr<struct timeval> tptr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_futimes(Thread *thread, sint fd,
ptr<struct timeval> tptr) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_truncate(Thread *thread, ptr<char> path,
off_t length) {
Ref<File> file;
auto result = thread->tproc->ops->open(thread, path, 2, 0, &file);
if (result.isError()) {
return result;
}
auto truncate = file->ops->truncate;
if (truncate == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
return truncate(file.get(), length, thread);
}
orbis::SysResult orbis::sys_freebsd6_truncate(Thread *thread, ptr<char> path,
sint, off_t length) {
return sys_truncate(thread, path, length);
}
orbis::SysResult orbis::sys_fsync(Thread *thread, sint fd) { return {}; }
orbis::SysResult orbis::sys_rename(Thread *thread, ptr<char> from,
ptr<char> to) {
if (auto rename = thread->tproc->ops->rename) {
return rename(thread, from, to);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_renameat(Thread *thread, sint oldfd, ptr<char> old,
sint newfd, ptr<char> new_) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mkdir(Thread *thread, ptr<char> path, sint mode) {
if (auto mkdir = thread->tproc->ops->mkdir) {
return mkdir(thread, path, mode);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mkdirat(Thread *thread, sint fd, ptr<char> path,
mode_t mode) {
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
auto mkdir = file->ops->mkdir;
if (mkdir == nullptr) {
return ErrorCode::NOTSUP;
}
std::lock_guard lock(file->mtx);
return mkdir(file.get(), path, mode);
}
orbis::SysResult orbis::sys_rmdir(Thread *thread, ptr<char> path) {
if (auto rmdir = thread->tproc->ops->rmdir) {
return rmdir(thread, path);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd,
ptr<char> buf, uint count,
ptr<slong> basep) {
ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count, basep);
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
std::lock_guard lock(file->mtx);
const orbis::Dirent *entries = file->dirEntries.data();
auto pos = file->nextOff / sizeof(orbis::Dirent); // TODO
auto rmax = count / sizeof(orbis::Dirent);
auto next = std::min<uint64_t>(file->dirEntries.size(), pos + rmax);
file->nextOff = next * sizeof(orbis::Dirent);
SysResult result{};
result = uwrite(ptr<orbis::Dirent>(buf), entries + pos, next - pos);
if (result.isError())
return result;
for (auto &entry : std::span(entries + pos, next - pos)) {
ORBIS_LOG_ERROR(__FUNCTION__, entry.name);
}
if (basep) {
result = uwrite(basep, slong(file->nextOff));
if (result.isError())
return result;
}
thread->retval[0] = (next - pos) * sizeof(orbis::Dirent);
return {};
}
orbis::SysResult orbis::sys_getdents(Thread *thread, sint fd, ptr<char> buf,
size_t count) {
ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count);
return orbis::sys_getdirentries(thread, fd, buf, count, nullptr);
}
orbis::SysResult orbis::sys_umask(Thread *thread, sint newmask) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_revoke(Thread *thread, ptr<char> path) {
ORBIS_LOG_WARNING(__FUNCTION__);
return {};
}
orbis::SysResult orbis::sys_lgetfh(Thread *thread, ptr<char> fname,
ptr<struct fhandle> fhp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_getfh(Thread *thread, ptr<char> fname,
ptr<struct fhandle> fhp) {
return ErrorCode::NOSYS;
}
orbis::SysResult
orbis::sys_fhopen(Thread *thread, ptr<const struct fhandle> u_fhp, sint flags) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fhstat(Thread *thread,
ptr<const struct fhandle> u_fhp,
ptr<Stat> sb) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_fhstatfs(Thread *thread,
ptr<const struct fhandle> u_fhp,
ptr<struct statfs> buf) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_posix_fallocate(Thread *thread, sint fd,
off_t offset, off_t len) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_posix_fadvise(Thread *thread, sint fd, off_t offset,
off_t len, sint advice) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,61 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys___acl_get_file(Thread *thread, ptr<char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_get_link(Thread *thread, ptr<const char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_set_file(Thread *thread, ptr<char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_set_link(Thread *thread, ptr<const char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_get_fd(Thread *thread, sint filedes,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_set_fd(Thread *thread, sint filedes,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_delete_link(Thread *thread,
ptr<const char> path,
acl_type_t type) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_delete_file(Thread *thread, ptr<char> path,
acl_type_t type) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_delete_fd(Thread *thread, sint filedes,
acl_type_t type) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_aclcheck_file(Thread *thread, ptr<char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_aclcheck_link(Thread *thread,
ptr<const char> path,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys___acl_aclcheck_fd(Thread *thread, sint filedes,
acl_type_t type,
ptr<struct acl> aclp) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,53 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_aio_return(Thread *thread,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_suspend(Thread *thread,
ptr<struct aiocb> aiocbp, sint nent,
ptr<const timespec> timeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_cancel(Thread *thread, sint fd,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_error(Thread *thread,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_oaio_read(Thread *thread,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_read(Thread *thread, ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_oaio_write(Thread *thread,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_write(Thread *thread,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_olio_listio(Thread *thread, sint mode,
ptr<cptr<struct aiocb>> acb_list,
sint nent, ptr<struct osigevent> sig) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_lio_listio(Thread *thread, sint mode,
ptr<cptr<struct aiocb>> aiocbp,
sint nent, ptr<struct sigevent> sig) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_waitcomplete(Thread *thread,
ptr<ptr<struct aiocb>> aiocbp,
ptr<timespec> timeout) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_aio_fsync(Thread *thread, sint op,
ptr<struct aiocb> aiocbp) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,23 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/Thread.hpp"
#include <mutex>
#include <string>
orbis::SysResult orbis::sys___getcwd(Thread *thread, ptr<char> buf,
uint buflen) {
std::string cwd;
{
std::lock_guard lock(thread->tproc->mtx);
cwd = std::string(thread->tproc->cwd);
}
if (buflen < cwd.size() + 1) {
return ErrorCode::NOMEM;
}
ORBIS_RET_ON_ERROR(uwriteRaw(buf, cwd.data(), cwd.size() + 1));
return {};
}

View file

@ -0,0 +1,79 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_extattrctl(Thread *thread, ptr<char> path, char cmd,
ptr<const char> filename,
sint attrnamespace,
ptr<const char> attrname) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_set_fd(Thread *thread, sint fd,
sint attrnamespace,
ptr<const char> attrname,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_set_file(Thread *thread, ptr<char> path,
sint attrnamespace,
ptr<const char> filename,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_set_link(Thread *thread,
ptr<const char> path,
sint attrnamespace,
ptr<const char> attrname,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_get_fd(Thread *thread, sint fd,
sint attrnamespace,
ptr<const char> attrname,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_get_file(Thread *thread, ptr<char> path,
sint attrnamespace,
ptr<const char> filename,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_get_link(Thread *thread,
ptr<const char> path,
sint attrnamespace,
ptr<const char> attrname,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_delete_fd(Thread *thread, sint fd,
sint attrnamespace,
ptr<const char> attrname) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_delete_file(Thread *thread, ptr<char> path,
sint attrnamespace,
ptr<const char> attrname) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_delete_link(Thread *thread,
ptr<const char> path,
sint attrnamespace,
ptr<const char> attrname) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_list_fd(Thread *thread, sint fd,
sint attrnamespace, ptr<void> data,
size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_list_file(Thread *thread,
ptr<const char> path,
sint attrnamespace,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_extattr_list_link(Thread *thread,
ptr<const char> path,
sint attrnamespace,
ptr<void> data, size_t nbytes) {
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,27 @@
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
orbis::SysResult orbis::sys_mount(Thread *thread, ptr<char> type,
ptr<char> path, sint flags, caddr_t data) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_unmount(Thread *thread, ptr<char> path,
sint flags) {
if (auto unmount = thread->tproc->ops->unmount) {
return unmount(thread, path, flags);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_nmount(Thread *thread, ptr<IoVec> iovp, uint iovcnt,
sint flags) {
if (auto nmount = thread->tproc->ops->nmount) {
return nmount(thread, iovp, iovcnt, flags);
}
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,104 @@
#include "error.hpp"
#include "sys/sysproto.hpp"
#include "thread/Process.hpp"
#include "thread/ProcessOps.hpp"
#include "thread/Thread.hpp"
orbis::SysResult orbis::sys_sbrk(Thread *, sint) {
return ErrorCode::OPNOTSUPP;
}
orbis::SysResult orbis::sys_sstk(Thread *, sint) {
return ErrorCode::OPNOTSUPP;
}
orbis::SysResult orbis::sys_mmap(Thread *thread, caddr_t addr, size_t len,
sint prot, sint flags, sint fd, off_t pos) {
if (auto impl = thread->tproc->ops->mmap) {
return impl(thread, addr, len, prot, flags, fd, pos);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_freebsd6_mmap(Thread *thread, caddr_t addr,
size_t len, sint prot, sint flags,
sint fd, sint, off_t pos) {
return sys_mmap(thread, addr, len, prot, flags, fd, pos);
}
orbis::SysResult orbis::sys_msync(Thread *thread, ptr<void> addr, size_t len,
sint flags) {
if (auto impl = thread->tproc->ops->msync) {
return impl(thread, addr, len, flags);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_munmap(Thread *thread, ptr<void> addr, size_t len) {
if (auto impl = thread->tproc->ops->munmap) {
return impl(thread, addr, len);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mprotect(Thread *thread, ptr<const void> addr,
size_t len, sint prot) {
if (auto impl = thread->tproc->ops->mprotect) {
return impl(thread, addr, len, prot);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_minherit(Thread *thread, ptr<void> addr, size_t len,
sint inherit) {
if (auto impl = thread->tproc->ops->minherit) {
return impl(thread, addr, len, inherit);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_madvise(Thread *thread, ptr<void> addr, size_t len,
sint behav) {
if (auto impl = thread->tproc->ops->madvise) {
return impl(thread, addr, len, behav);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mincore(Thread *thread, ptr<const void> addr,
size_t len, ptr<char> vec) {
if (auto impl = thread->tproc->ops->mincore) {
return impl(thread, addr, len, vec);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mlock(Thread *thread, ptr<const void> addr,
size_t len) {
if (auto impl = thread->tproc->ops->mlock) {
return impl(thread, addr, len);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_mlockall(Thread *thread, sint how) {
if (auto impl = thread->tproc->ops->mlockall) {
return impl(thread, how);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_munlockall(Thread *thread) {
if (auto impl = thread->tproc->ops->munlockall) {
return impl(thread);
}
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_munlock(Thread *thread, ptr<const void> addr,
size_t len) {
if (auto impl = thread->tproc->ops->munlock) {
return impl(thread, addr, len);
}
return ErrorCode::NOSYS;
}

View file

@ -0,0 +1,8 @@
#include "sys/sysproto.hpp"
orbis::SysResult orbis::sys_obreak(Thread *thread, ptr<char> nsize) {
return ErrorCode::NOSYS;
}
orbis::SysResult orbis::sys_ovadvise(Thread *thread, sint anom) {
return ErrorCode::NOSYS;
}

3237
kernel/orbis/src/sysvec.cpp Normal file

File diff suppressed because it is too large Load diff

891
kernel/orbis/src/umtx.cpp Normal file
View file

@ -0,0 +1,891 @@
#include "umtx.hpp"
#include "error.hpp"
#include "orbis/KernelContext.hpp"
#include "orbis/thread.hpp"
#include "orbis/utils/Logs.hpp"
#include <limits>
namespace orbis {
std::pair<const UmtxKey, UmtxCond> *UmtxChain::enqueue(UmtxKey &key,
Thread *thr) {
if (!spare_queue.empty()) {
auto node = spare_queue.extract(spare_queue.begin());
node.key() = key;
node.mapped().thr = thr;
return &*sleep_queue.insert(std::move(node));
}
return &*sleep_queue.emplace(key, thr);
}
void UmtxChain::erase(std::pair<const UmtxKey, UmtxCond> *obj) {
for (auto [it, e] = sleep_queue.equal_range(obj->first); it != e; it++) {
if (&*it == obj) {
erase(it);
return;
}
}
}
UmtxChain::queue_type::iterator UmtxChain::erase(queue_type::iterator it) {
auto next = std::next(it);
auto node = sleep_queue.extract(it);
node.key() = {};
spare_queue.insert(spare_queue.begin(), std::move(node));
return next;
}
uint UmtxChain::notify_n(const UmtxKey &key, sint count) {
auto it = sleep_queue.find(key);
if (it == sleep_queue.end())
return 0;
uint n = 0;
while (count > 0) {
it->second.thr = nullptr;
it->second.cv.notify_all(mtx);
it = erase(it);
n++;
count--;
if (it == sleep_queue.end() || it->first != key) {
break;
}
}
return n;
}
uint UmtxChain::notify_one(const UmtxKey &key) { return notify_n(key, 1); }
uint UmtxChain::notify_all(const UmtxKey &key) {
return notify_n(key, std::numeric_limits<sint>::max());
}
} // namespace orbis
orbis::ErrorCode orbis::umtx_lock_umtx(Thread *thread, ptr<umtx> umtx, ulong id,
std::uint64_t ut) {
ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id, ut);
std::abort();
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_unlock_umtx(Thread *thread, ptr<umtx> umtx,
ulong id) {
ORBIS_LOG_TODO(__FUNCTION__, thread->tid, umtx, id);
std::abort();
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_wait(Thread *thread, ptr<void> addr, ulong id,
std::uint64_t ut, bool is32, bool ipc) {
ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, addr, id, ut, is32);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, ipc, addr);
auto node = chain.enqueue(key, thread);
ErrorCode result = {};
ulong val = 0;
if (is32)
val = reinterpret_cast<ptr<std::atomic<uint>>>(addr)->load();
else
val = reinterpret_cast<ptr<std::atomic<ulong>>>(addr)->load();
if (val == id) {
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx));
if ((result != ErrorCode{}) || node->second.thr != thread)
break;
}
} else {
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
break;
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= ut) {
result = ErrorCode::TIMEDOUT;
break;
}
if (result != ErrorCode{}) {
break;
}
}
}
}
ORBIS_LOG_NOTICE(__FUNCTION__, "wakeup", thread->tid, addr);
if (node->second.thr == thread)
chain.erase(node);
return result;
}
orbis::ErrorCode orbis::umtx_wake(Thread *thread, ptr<void> addr, sint n_wake) {
ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, addr, n_wake);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, true, addr);
if (key.pid == 0) {
// IPC workaround (TODO)
chain.notify_all(key);
return {};
}
chain.notify_n(key, n_wake);
return {};
}
namespace orbis {
enum class umutex_lock_mode {
lock,
try_,
wait,
};
template <>
void log_class_string<umutex_lock_mode>::format(std::string &out,
const void *arg) {
switch (get_object(arg)) {
case umutex_lock_mode::lock:
out += "lock";
break;
case umutex_lock_mode::try_:
out += "try";
break;
case umutex_lock_mode::wait:
out += "wait";
break;
}
}
static ErrorCode do_lock_normal(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags, ut, mode);
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m);
ErrorCode error = {};
while (true) {
int owner = m->owner.load(std::memory_order_acquire);
if (mode == umutex_lock_mode::wait) {
if (owner == kUmutexUnowned || owner == kUmutexContested)
return {};
} else {
owner = kUmutexUnowned;
if (m->owner.compare_exchange_strong(owner, thread->tid))
return {};
if (owner == kUmutexContested) {
if (m->owner.compare_exchange_strong(owner,
thread->tid | kUmutexContested))
return {};
continue;
}
}
if ((flags & kUmutexErrorCheck) != 0 &&
(owner & ~kUmutexContested) == thread->tid)
return ErrorCode::DEADLK;
if (mode == umutex_lock_mode::try_)
return ErrorCode::BUSY;
if (error != ErrorCode{})
return error;
auto node = chain.enqueue(key, thread);
if (m->owner.compare_exchange_strong(owner, owner | kUmutexContested)) {
{
orbis::scoped_unblock unblock;
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
}
if (error == ErrorCode{} && node->second.thr == thread &&
m->owner.load() != 0) {
error = ErrorCode::TIMEDOUT;
}
}
if (node->second.thr == thread)
chain.erase(node);
}
}
static ErrorCode do_lock_pi(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
// ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode);
return do_lock_normal(thread, m, flags, ut, mode);
}
static ErrorCode do_lock_pp(Thread *thread, ptr<umutex> m, uint flags,
std::uint64_t ut, umutex_lock_mode mode) {
// ORBIS_LOG_TODO(__FUNCTION__, m, flags, ut, mode);
return do_lock_normal(thread, m, flags, ut, mode);
}
static ErrorCode do_unlock_normal(Thread *thread, ptr<umutex> m, uint flags) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, flags);
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m);
int owner = m->owner.load(std::memory_order_acquire);
if ((owner & ~kUmutexContested) != thread->tid)
return ErrorCode::PERM;
if ((owner & kUmtxContested) == 0) {
if (m->owner.compare_exchange_strong(owner, kUmutexUnowned))
return {};
}
std::size_t count = chain.sleep_queue.count(key);
bool ok;
if (key.pid == 0) {
ok = m->owner.compare_exchange_strong(owner, kUmutexUnowned);
// IPC workaround (TODO)
chain.notify_all(key);
if (!ok)
return ErrorCode::INVAL;
return {};
}
ok = m->owner.compare_exchange_strong(owner, count <= 1 ? kUmutexUnowned
: kUmutexContested);
chain.notify_one(key);
if (!ok)
return ErrorCode::INVAL;
return {};
}
static ErrorCode do_unlock_pi(Thread *thread, ptr<umutex> m, uint flags) {
return do_unlock_normal(thread, m, flags);
}
static ErrorCode do_unlock_pp(Thread *thread, ptr<umutex> m, uint flags) {
ORBIS_LOG_TODO(__FUNCTION__, m, flags);
return do_unlock_normal(thread, m, flags);
}
} // namespace orbis
orbis::ErrorCode orbis::umtx_trylock_umutex(Thread *thread, ptr<umutex> m) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, 0, umutex_lock_mode::try_);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, 0, umutex_lock_mode::try_);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, 0, umutex_lock_mode::try_);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_lock_umutex(Thread *thread, ptr<umutex> m,
std::uint64_t ut) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m, ut);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::lock);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::lock);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::lock);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_unlock_umutex(Thread *thread, ptr<umutex> m) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_unlock_normal(thread, m, flags);
case kUmutexPrioInherit:
return do_unlock_pi(thread, m, flags);
case kUmutexPrioProtect:
return do_unlock_pp(thread, m, flags);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_set_ceiling(Thread *thread, ptr<umutex> m,
std::uint32_t ceiling,
ptr<uint32_t> oldCeiling) {
ORBIS_LOG_TRACE(__FUNCTION__, m, ceiling, oldCeiling);
std::abort();
return ErrorCode::NOSYS;
}
orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr<ucond> cv,
ptr<umutex> m, std::uint64_t ut,
ulong wflags) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv, m, ut, wflags);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
if ((wflags & ~(kCvWaitAbsTime | kCvWaitClockId))) {
ORBIS_LOG_FATAL("umtx_cv_wait: UNKNOWN wflags", wflags);
return ErrorCode::INVAL;
}
if ((wflags & kCvWaitClockId) != 0 && ut + 1) {
ORBIS_LOG_WARNING("umtx_cv_wait: CLOCK_ID", wflags, cv->clockid);
}
if ((wflags & kCvWaitAbsTime) != 0 && ut + 1) {
ORBIS_LOG_WARNING("umtx_cv_wait: ABSTIME", wflags);
auto now = std::chrono::time_point_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now())
.time_since_epoch()
.count();
if (now > ut) {
ut = 0;
} else {
ut = ut - now;
}
}
auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv);
auto node = chain.enqueue(key, thread);
if (!cv->has_waiters.load(std::memory_order::relaxed)) {
cv->has_waiters.store(1, std::memory_order::relaxed);
}
ErrorCode result = umtx_unlock_umutex(thread, m);
if (result == ErrorCode{}) {
orbis::scoped_unblock unblock;
if (ut + 1 == 0) {
while (true) {
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (result != ErrorCode{} || node->second.thr != thread) {
break;
}
}
} else {
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread) {
break;
}
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= ut) {
result = ErrorCode::TIMEDOUT;
break;
}
if (result != ErrorCode{}) {
break;
}
}
}
}
if (node->second.thr != thread) {
result = {};
} else {
chain.erase(node);
if (chain.sleep_queue.count(key) == 0)
cv->has_waiters.store(0, std::memory_order::relaxed);
}
return result;
}
orbis::ErrorCode orbis::umtx_cv_signal(Thread *thread, ptr<ucond> cv) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv);
if (key.pid == 0) {
// IPC workaround (TODO)
chain.notify_all(key);
cv->has_waiters = 0;
return {};
}
std::size_t count = chain.sleep_queue.count(key);
if (chain.notify_one(key) >= count)
cv->has_waiters.store(0, std::memory_order::relaxed);
return {};
}
orbis::ErrorCode orbis::umtx_cv_broadcast(Thread *thread, ptr<ucond> cv) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, cv);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, cv->flags, cv);
chain.notify_all(key);
cv->has_waiters.store(0, std::memory_order::relaxed);
return {};
}
orbis::ErrorCode orbis::umtx_rw_rdlock(Thread *thread, ptr<urwlock> rwlock,
slong fflag, ulong ut) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, rwlock, fflag, ut);
auto flags = rwlock->flags;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags & 1, rwlock);
auto wrflags = kUrwLockWriteOwner;
if (!(fflag & kUrwLockPreferReader) && !(flags & kUrwLockPreferReader)) {
wrflags |= kUrwLockWriteWaiters;
}
while (true) {
auto state = rwlock->state.load(std::memory_order::relaxed);
while ((state & wrflags) == 0) {
if ((state & kUrwLockMaxReaders) == kUrwLockMaxReaders) {
return ErrorCode::AGAIN;
}
if (rwlock->state.compare_exchange_strong(state, state + 1)) {
return {};
}
}
while ((state & wrflags) && !(state & kUrwLockReadWaiters)) {
if (rwlock->state.compare_exchange_weak(state,
state | kUrwLockReadWaiters)) {
break;
}
}
if (!(state & wrflags)) {
continue;
}
++rwlock->blocked_readers;
ErrorCode result{};
while (state & wrflags) {
auto node = chain.enqueue(key, thread);
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if (result != ErrorCode{} || node->second.thr != thread) {
break;
}
}
} else {
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
break;
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= ut) {
result = ErrorCode::TIMEDOUT;
break;
}
if (result != ErrorCode{}) {
break;
}
}
}
if (node->second.thr != thread) {
result = {};
} else {
chain.erase(node);
}
if (result != ErrorCode{}) {
break;
}
state = rwlock->state.load(std::memory_order::relaxed);
}
if (--rwlock->blocked_readers == 0) {
while (true) {
if (!rwlock->state.compare_exchange_weak(
state, state & ~kUrwLockReadWaiters)) {
break;
}
}
}
}
return {};
}
orbis::ErrorCode orbis::umtx_rw_wrlock(Thread *thread, ptr<urwlock> rwlock,
ulong ut) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, rwlock, ut);
auto flags = rwlock->flags;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags & 1, rwlock);
uint32_t blocked_readers = 0;
ErrorCode error = {};
while (true) {
auto state = rwlock->state.load(std::memory_order::relaxed);
while (!(state & kUrwLockWriteOwner) && (state & kUrwLockMaxReaders) == 0) {
if (!rwlock->state.compare_exchange_strong(state,
state | kUrwLockWriteOwner)) {
return {};
}
}
if (error != ErrorCode{}) {
if (!(state & (kUrwLockWriteOwner | kUrwLockWriteWaiters)) &&
blocked_readers != 0) {
chain.notify_one(key);
}
break;
}
state = rwlock->state.load(std::memory_order::relaxed);
while (
((state & kUrwLockWriteOwner) || (state & kUrwLockMaxReaders) != 0) &&
(state & kUrwLockWriteWaiters) == 0) {
if (!rwlock->state.compare_exchange_strong(
state, state | kUrwLockWriteWaiters)) {
break;
}
}
if (!(state & kUrwLockWriteOwner) && (state & kUrwLockMaxReaders) == 0) {
continue;
}
++rwlock->blocked_writers;
while ((state & kUrwLockWriteOwner) || (state & kUrwLockMaxReaders) != 0) {
auto node = chain.enqueue(key, thread);
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
error = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if ((error != ErrorCode{}) || node->second.thr != thread) {
break;
}
}
} else {
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
error =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
break;
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= ut) {
error = ErrorCode::TIMEDOUT;
break;
}
if (error != ErrorCode{}) {
break;
}
}
}
if (node->second.thr != thread) {
error = {};
} else {
chain.erase(node);
}
if (error != ErrorCode{}) {
break;
}
state = rwlock->state.load(std::memory_order::relaxed);
}
if (--rwlock->blocked_writers == 0) {
state = rwlock->state.load(std::memory_order::relaxed);
while (true) {
if (rwlock->state.compare_exchange_weak(
state, state & ~kUrwLockWriteWaiters)) {
break;
}
}
blocked_readers = rwlock->blocked_readers;
} else {
blocked_readers = 0;
}
}
return error;
}
orbis::ErrorCode orbis::umtx_rw_unlock(Thread *thread, ptr<urwlock> rwlock) {
auto flags = rwlock->flags;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags & 1, rwlock);
auto state = rwlock->state.load(std::memory_order::relaxed);
if (state & kUrwLockWriteOwner) {
while (true) {
if (rwlock->state.compare_exchange_weak(state,
state & ~kUrwLockWriteOwner)) {
break;
}
if (!(state & kUrwLockWriteOwner)) {
return ErrorCode::PERM;
}
}
} else if ((state & kUrwLockMaxReaders) != 0) {
while (true) {
if (rwlock->state.compare_exchange_weak(state, state - 1)) {
break;
}
if ((state & kUrwLockMaxReaders) == 0) {
return ErrorCode::PERM;
}
}
} else {
return ErrorCode::PERM;
}
unsigned count = 0;
if (!(flags & kUrwLockPreferReader)) {
if (state & kUrwLockWriteWaiters) {
count = 1;
} else if (state & kUrwLockReadWaiters) {
count = UINT_MAX;
}
} else {
if (state & kUrwLockReadWaiters) {
count = UINT_MAX;
} else if (state & kUrwLockWriteWaiters) {
count = 1;
}
}
if (flags & 1) {
chain.notify_all(key);
} else {
chain.notify_n(key, count);
}
return {};
}
orbis::ErrorCode orbis::umtx_wake_private(Thread *thread, ptr<void> addr,
sint n_wake) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, addr, n_wake);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, false, addr);
chain.notify_n(key, n_wake);
return {};
}
orbis::ErrorCode orbis::umtx_wait_umutex(Thread *thread, ptr<umutex> m,
std::uint64_t ut) {
ORBIS_LOG_TRACE(__FUNCTION__, m, ut);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
switch (flags & (kUmutexPrioInherit | kUmutexPrioProtect)) {
case 0:
return do_lock_normal(thread, m, flags, ut, umutex_lock_mode::wait);
case kUmutexPrioInherit:
return do_lock_pi(thread, m, flags, ut, umutex_lock_mode::wait);
case kUmutexPrioProtect:
return do_lock_pp(thread, m, flags, ut, umutex_lock_mode::wait);
}
return ErrorCode::INVAL;
}
orbis::ErrorCode orbis::umtx_wake_umutex(Thread *thread, ptr<umutex> m,
sint wakeFlags) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, m);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, flags, m);
int owner = m->owner.load(std::memory_order::acquire);
if ((owner & ~kUmutexContested) != 0)
return {};
std::size_t count = chain.sleep_queue.count(key);
if (count <= 1) {
owner = kUmutexContested;
m->owner.compare_exchange_strong(owner, kUmutexUnowned);
}
if (count != 0 && (owner & ~kUmutexContested) == 0) {
if (flags & 1) {
chain.notify_all(key);
} else {
chain.notify_one(key);
}
}
return {};
}
orbis::ErrorCode orbis::umtx_sem_wait(Thread *thread, ptr<usem> sem,
std::uint64_t ut) {
ORBIS_LOG_TRACE(__FUNCTION__, sem, ut);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem);
auto node = chain.enqueue(key, thread);
std::uint32_t has_waiters = sem->has_waiters;
if (!has_waiters)
sem->has_waiters.compare_exchange_strong(has_waiters, 1);
ErrorCode result = {};
if (!sem->count) {
if (ut + 1 == 0) {
while (true) {
orbis::scoped_unblock unblock;
result = orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut));
if ((result != ErrorCode{}) || node->second.thr != thread)
break;
}
} else {
auto start = std::chrono::steady_clock::now();
std::uint64_t udiff = 0;
while (true) {
orbis::scoped_unblock unblock;
result =
orbis::toErrorCode(node->second.cv.wait(chain.mtx, ut - udiff));
if (node->second.thr != thread)
break;
udiff = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count();
if (udiff >= ut) {
result = ErrorCode::TIMEDOUT;
break;
}
if (result != ErrorCode{}) {
break;
}
}
}
}
if (node->second.thr != thread) {
result = {};
} else {
chain.erase(node);
}
return result;
}
orbis::ErrorCode orbis::umtx_sem_wake(Thread *thread, ptr<usem> sem) {
ORBIS_LOG_TRACE(__FUNCTION__, sem);
auto [chain, key, lock] = g_context.getUmtxChain0(thread, sem->flags, sem);
if (key.pid == 0) {
// IPC workaround (TODO)
chain.notify_all(key);
sem->has_waiters = 0;
return {};
}
std::size_t count = chain.sleep_queue.count(key);
if (chain.notify_one(key) >= count)
sem->has_waiters.store(0, std::memory_order::relaxed);
return {};
}
orbis::ErrorCode orbis::umtx_nwake_private(Thread *thread, ptr<void *> uaddrs,
std::int64_t count) {
ORBIS_LOG_TRACE(__FUNCTION__, thread->tid, uaddrs, count);
while (count-- > 0) {
void *uaddr;
auto error = uread(uaddr, uaddrs++);
if (error != ErrorCode{})
return error;
umtx_wake_private(thread, uaddr, 1);
}
return {};
}
orbis::ErrorCode orbis::umtx_wake2_umutex(Thread *thread, ptr<umutex> m,
sint wakeFlags) {
ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, m);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, wakeFlags & 1, m);
int owner = 0;
std::size_t count = chain.sleep_queue.count(key);
if (count > 1) {
owner = m->owner.load(std::memory_order::acquire);
while ((owner & kUmutexContested) == 0) {
if (m->owner.compare_exchange_weak(owner, owner | kUmutexContested)) {
break;
}
}
} else if (count == 1) {
owner = m->owner.load(std::memory_order::acquire);
while ((owner & ~kUmutexContested) != 0 &&
(owner & kUmutexContested) == 0) {
if (m->owner.compare_exchange_weak(owner, owner | kUmutexContested)) {
break;
}
}
}
if (count != 0 && (owner & ~kUmutexContested) == 0) {
chain.notify_one(key);
return {};
}
return {};
}
orbis::ErrorCode orbis::umtx_wake3_umutex(Thread *thread, ptr<umutex> m,
sint wakeFlags) {
ORBIS_LOG_NOTICE(__FUNCTION__, thread->tid, m);
uint flags;
if (ErrorCode err = uread(flags, &m->flags); err != ErrorCode{})
return err;
auto [chain, key, lock] = g_context.getUmtxChain1(thread, wakeFlags & 1, m);
int owner = 0;
std::size_t count = chain.sleep_queue.count(key);
if (count > 1) {
owner = m->owner.load(std::memory_order::acquire);
while ((owner & kUmutexContested) == 0) {
if (m->owner.compare_exchange_weak(owner, owner | kUmutexContested)) {
break;
}
}
} else if (count == 1) {
owner = m->owner.load(std::memory_order::acquire);
while ((owner & ~kUmutexContested) != 0 &&
(owner & kUmutexContested) == 0) {
if (m->owner.compare_exchange_weak(owner, owner | kUmutexContested)) {
break;
}
}
}
if (count != 0 && (owner & ~kUmutexContested) == 0) {
chain.notify_one(key);
}
return {};
}

View file

@ -0,0 +1,545 @@
#include "utils/Logs.hpp"
#include "error/ErrorCode.hpp"
#include <cstdarg>
#include <cstdint>
#include <sstream>
#include <string>
#include <string_view>
#include <unistd.h>
#include <vector>
static void append_hex(std::string &out, std::unsigned_integral auto value) {
std::ostringstream buf;
if (value < 10)
buf << value;
else if (value >= decltype(value)(UINTMAX_MAX) - 1)
buf << "-" << std::uintmax_t(decltype(value)(-value));
else
buf << "0x" << std::hex << std::uintmax_t(value);
out += buf.str();
}
namespace orbis::logs {
void log_class_string<void *>::format(std::string &out, const void *arg) {
const void *ptr = *reinterpret_cast<const void *const *>(arg);
append_hex(out, reinterpret_cast<std::uintptr_t>(ptr));
}
void log_class_string<char *>::format_n(std::string &out, const void *arg,
std::size_t n) {
const char *ptr = reinterpret_cast<const char *>(arg);
const auto addr = reinterpret_cast<std::uintptr_t>(ptr);
const auto _end = n ? addr + n - 1 : addr;
if (addr < 0x10000 || std::max(n, _end) > 0x7fff'ffff'ffff) {
out += "{{{{{BAD_ADDR:";
append_hex(out, addr);
out += "}}}}}";
return;
}
while (n--) {
const char c = *ptr++;
if (!c)
break;
out += c;
}
}
void log_class_string<char *>::format(std::string &out, const void *arg) {
const char *ptr = *reinterpret_cast<const char *const *>(arg);
const auto addr = reinterpret_cast<std::uintptr_t>(ptr);
if (addr < 0x10000 || addr > 0x7fff'ffff'ffff) {
out += "{{{{{BAD_ADDR:";
append_hex(out, addr);
out += "}}}}}";
return;
}
out += ptr;
}
template <>
void log_class_string<std::string>::format(std::string &out, const void *arg) {
out += get_object(arg);
}
template <>
void log_class_string<std::string_view>::format(std::string &out,
const void *arg) {
out += get_object(arg);
}
template <>
void log_class_string<std::vector<char>>::format(std::string &out,
const void *arg) {
const std::vector<char> &obj = get_object(arg);
out.append(obj.cbegin(), obj.cend());
}
template <>
void log_class_string<std::u8string>::format(std::string &out,
const void *arg) {
const std::u8string &obj = get_object(arg);
out.append(obj.cbegin(), obj.cend());
}
template <>
void log_class_string<std::u8string_view>::format(std::string &out,
const void *arg) {
const std::u8string_view &obj = get_object(arg);
out.append(obj.cbegin(), obj.cend());
}
template <>
void log_class_string<std::vector<char8_t>>::format(std::string &out,
const void *arg) {
const std::vector<char8_t> &obj = get_object(arg);
out.append(obj.cbegin(), obj.cend());
}
template <>
void log_class_string<char>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<unsigned char>(get_object(arg)));
}
template <>
void log_class_string<unsigned char>::format(std::string &out,
const void *arg) {
append_hex(out, get_object(arg));
}
template <>
void log_class_string<signed char>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<unsigned char>(get_object(arg)));
}
template <>
void log_class_string<short>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<unsigned short>(get_object(arg)));
}
template <>
void log_class_string<ushort>::format(std::string &out, const void *arg) {
append_hex(out, get_object(arg));
}
template <>
void log_class_string<int>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<uint>(get_object(arg)));
}
template <>
void log_class_string<uint>::format(std::string &out, const void *arg) {
append_hex(out, get_object(arg));
}
template <>
void log_class_string<long>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<unsigned long>(get_object(arg)));
}
template <>
void log_class_string<ulong>::format(std::string &out, const void *arg) {
append_hex(out, get_object(arg));
}
template <>
void log_class_string<long long>::format(std::string &out, const void *arg) {
append_hex(out, static_cast<unsigned long long>(get_object(arg)));
}
template <>
void log_class_string<unsigned long long>::format(std::string &out,
const void *arg) {
append_hex(out, get_object(arg));
}
template <>
void log_class_string<float>::format(std::string &out, const void *arg) {
std::ostringstream buf(out, std::ios_base::ate);
buf << get_object(arg);
}
template <>
void log_class_string<double>::format(std::string &out, const void *arg) {
std::ostringstream buf(out, std::ios_base::ate);
buf << get_object(arg);
}
template <>
void log_class_string<bool>::format(std::string &out, const void *arg) {
out += get_object(arg) ? "1" : "0";
}
template <>
void log_class_string<orbis::ErrorCode>::format(std::string &out,
const void *arg) {
auto errorCode = get_object(arg);
switch (errorCode) {
case ErrorCode::PERM:
out += "PERM";
return;
case ErrorCode::NOENT:
out += "NOENT";
return;
case ErrorCode::SRCH:
out += "SRCH";
return;
case ErrorCode::INTR:
out += "INTR";
return;
case ErrorCode::IO:
out += "IO";
return;
case ErrorCode::NXIO:
out += "NXIO";
return;
case ErrorCode::TOOBIG:
out += "TOOBIG";
return;
case ErrorCode::NOEXEC:
out += "NOEXEC";
return;
case ErrorCode::BADF:
out += "BADF";
return;
case ErrorCode::CHILD:
out += "CHILD";
return;
case ErrorCode::DEADLK:
out += "DEADLK";
return;
case ErrorCode::NOMEM:
out += "NOMEM";
return;
case ErrorCode::ACCES:
out += "ACCES";
return;
case ErrorCode::FAULT:
out += "FAULT";
return;
case ErrorCode::NOTBLK:
out += "NOTBLK";
return;
case ErrorCode::BUSY:
out += "BUSY";
return;
case ErrorCode::EXIST:
out += "EXIST";
return;
case ErrorCode::XDEV:
out += "XDEV";
return;
case ErrorCode::NODEV:
out += "NODEV";
return;
case ErrorCode::NOTDIR:
out += "NOTDIR";
return;
case ErrorCode::ISDIR:
out += "ISDIR";
return;
case ErrorCode::INVAL:
out += "INVAL";
return;
case ErrorCode::NFILE:
out += "NFILE";
return;
case ErrorCode::MFILE:
out += "MFILE";
return;
case ErrorCode::NOTTY:
out += "NOTTY";
return;
case ErrorCode::TXTBSY:
out += "TXTBSY";
return;
case ErrorCode::FBIG:
out += "FBIG";
return;
case ErrorCode::NOSPC:
out += "NOSPC";
return;
case ErrorCode::SPIPE:
out += "SPIPE";
return;
case ErrorCode::ROFS:
out += "ROFS";
return;
case ErrorCode::MLINK:
out += "MLINK";
return;
case ErrorCode::PIPE:
out += "PIPE";
return;
case ErrorCode::DOM:
out += "DOM";
return;
case ErrorCode::RANGE:
out += "RANGE";
return;
case ErrorCode::AGAIN:
out += "AGAIN";
return;
case ErrorCode::INPROGRESS:
out += "INPROGRESS";
return;
case ErrorCode::ALREADY:
out += "ALREADY";
return;
case ErrorCode::NOTSOCK:
out += "NOTSOCK";
return;
case ErrorCode::DESTADDRREQ:
out += "DESTADDRREQ";
return;
case ErrorCode::MSGSIZE:
out += "MSGSIZE";
return;
case ErrorCode::PROTOTYPE:
out += "PROTOTYPE";
return;
case ErrorCode::NOPROTOOPT:
out += "NOPROTOOPT";
return;
case ErrorCode::PROTONOSUPPORT:
out += "PROTONOSUPPORT";
return;
case ErrorCode::SOCKTNOSUPPORT:
out += "SOCKTNOSUPPORT";
return;
case ErrorCode::OPNOTSUPP:
out += "OPNOTSUPP";
return;
case ErrorCode::PFNOSUPPORT:
out += "PFNOSUPPORT";
return;
case ErrorCode::AFNOSUPPORT:
out += "AFNOSUPPORT";
return;
case ErrorCode::ADDRINUSE:
out += "ADDRINUSE";
return;
case ErrorCode::ADDRNOTAVAIL:
out += "ADDRNOTAVAIL";
return;
case ErrorCode::NETDOWN:
out += "NETDOWN";
return;
case ErrorCode::NETUNREACH:
out += "NETUNREACH";
return;
case ErrorCode::NETRESET:
out += "NETRESET";
return;
case ErrorCode::CONNABORTED:
out += "CONNABORTED";
return;
case ErrorCode::CONNRESET:
out += "CONNRESET";
return;
case ErrorCode::NOBUFS:
out += "NOBUFS";
return;
case ErrorCode::ISCONN:
out += "ISCONN";
return;
case ErrorCode::NOTCONN:
out += "NOTCONN";
return;
case ErrorCode::SHUTDOWN:
out += "SHUTDOWN";
return;
case ErrorCode::TOOMANYREFS:
out += "TOOMANYREFS";
return;
case ErrorCode::TIMEDOUT:
out += "TIMEDOUT";
return;
case ErrorCode::CONNREFUSED:
out += "CONNREFUSED";
return;
case ErrorCode::LOOP:
out += "LOOP";
return;
case ErrorCode::NAMETOOLONG:
out += "NAMETOOLONG";
return;
case ErrorCode::HOSTDOWN:
out += "HOSTDOWN";
return;
case ErrorCode::HOSTUNREACH:
out += "HOSTUNREACH";
return;
case ErrorCode::NOTEMPTY:
out += "NOTEMPTY";
return;
case ErrorCode::PROCLIM:
out += "PROCLIM";
return;
case ErrorCode::USERS:
out += "USERS";
return;
case ErrorCode::DQUOT:
out += "DQUOT";
return;
case ErrorCode::STALE:
out += "STALE";
return;
case ErrorCode::REMOTE:
out += "REMOTE";
return;
case ErrorCode::BADRPC:
out += "BADRPC";
return;
case ErrorCode::RPCMISMATCH:
out += "RPCMISMATCH";
return;
case ErrorCode::PROGUNAVAIL:
out += "PROGUNAVAIL";
return;
case ErrorCode::PROGMISMATCH:
out += "PROGMISMATCH";
return;
case ErrorCode::PROCUNAVAIL:
out += "PROCUNAVAIL";
return;
case ErrorCode::NOLCK:
out += "NOLCK";
return;
case ErrorCode::NOSYS:
out += "NOSYS";
return;
case ErrorCode::FTYPE:
out += "FTYPE";
return;
case ErrorCode::AUTH:
out += "AUTH";
return;
case ErrorCode::NEEDAUTH:
out += "NEEDAUTH";
return;
case ErrorCode::IDRM:
out += "IDRM";
return;
case ErrorCode::NOMSG:
out += "NOMSG";
return;
case ErrorCode::OVERFLOW:
out += "OVERFLOW";
return;
case ErrorCode::CANCELED:
out += "CANCELED";
return;
case ErrorCode::ILSEQ:
out += "ILSEQ";
return;
case ErrorCode::NOATTR:
out += "NOATTR";
return;
case ErrorCode::DOOFUS:
out += "DOOFUS";
return;
case ErrorCode::BADMSG:
out += "BADMSG";
return;
case ErrorCode::MULTIHOP:
out += "MULTIHOP";
return;
case ErrorCode::NOLINK:
out += "NOLINK";
return;
case ErrorCode::PROTO:
out += "PROTO";
return;
case ErrorCode::NOTCAPABLE:
out += "NOTCAPABLE";
return;
case ErrorCode::CAPMODE:
out += "CAPMODE";
return;
}
out += "<unknown " + std::to_string((int)errorCode) + ">";
}
void _orbis_log_print(LogLevel lvl, std::string_view msg,
std::string_view names, const log_type_info *sup, ...) {
if (lvl > logs_level.load(std::memory_order::relaxed)) {
return;
}
/*constinit thread_local*/ std::string text;
/*constinit thread_local*/ std::vector<const void *> args;
std::size_t args_count = 0;
for (auto v = sup; v && v->log_string; v++)
args_count++;
text.reserve(50000);
args.resize(args_count);
va_list c_args;
va_start(c_args, sup);
for (const void *&arg : args)
arg = va_arg(c_args, const void *);
va_end(c_args);
text += msg;
if (args_count)
text += "(";
for (std::size_t i = 0; i < args_count; i++) {
if (i)
text += ", ";
names.remove_prefix(
std::min(names.find_first_not_of(" \t\n\r"), names.length()));
std::string_view name = names.substr(0, names.find_first_of(','));
names.remove_prefix(std::min(name.size() + 1, names.size()));
text += name;
if (!name.empty() &&
(name[0] == '"' || (name[0] >= '0' && name[0] <= '9'))) {
// skip literals
continue;
}
text += "=";
sup[i].log_string(text, args[i]);
}
if (args_count)
text += ")";
const char *color = "";
switch (lvl) {
case LogLevel::Always:
color = "\e[36;1m";
break;
case LogLevel::Fatal:
color = "\e[35;1m";
break;
case LogLevel::Error:
color = "\e[0;31m";
break;
case LogLevel::Todo:
color = "\e[1;33m";
break;
case LogLevel::Success:
color = "\e[1;32m";
break;
case LogLevel::Warning:
color = "\e[0;33m";
break;
case LogLevel::Notice:
color = "\e[0;36m";
break;
case LogLevel::Trace:
color = "";
break;
}
static const bool istty = isatty(fileno(stderr));
if (istty) {
std::fprintf(stderr, "%s%s\e[0m\n", color, text.c_str());
} else {
std::fprintf(stderr, "%s\n", text.c_str());
}
}
} // namespace orbis::logs

View file

@ -0,0 +1,118 @@
#include "utils/SharedAtomic.hpp"
using namespace orbis;
#ifdef ORBIS_HAS_FUTEX
#include <linux/futex.h>
std::errc shared_atomic32::wait_impl(std::uint32_t oldValue,
std::chrono::microseconds usec_timeout) {
auto usec_timeout_count = usec_timeout.count();
struct timespec timeout{};
bool useTimeout = usec_timeout != std::chrono::microseconds::max();
if (useTimeout) {
timeout.tv_nsec = (usec_timeout_count % 1000'000) * 1000;
timeout.tv_sec = (usec_timeout_count / 1000'000);
}
bool unblock = (!useTimeout || usec_timeout.count() > 1000) &&
g_scopedUnblock != nullptr;
if (unblock) {
if (!g_scopedUnblock(true)) {
return std::errc::interrupted;
}
}
int result = syscall(SYS_futex, this, FUTEX_WAIT, oldValue,
useTimeout ? &timeout : nullptr);
auto errorCode = result < 0 ? static_cast<std::errc>(errno) : std::errc{};
if (unblock) {
if (!g_scopedUnblock(false)) {
if (result < 0) {
return std::errc::interrupted;
}
return {};
}
}
if (result < 0) {
return errorCode;
}
return {};
}
int shared_atomic32::notify_n(int count) const {
return syscall(SYS_futex, this, FUTEX_WAKE, count);
}
#elif defined(ORBIS_HAS_ULOCK)
#include <limits>
#define UL_COMPARE_AND_WAIT 1
#define UL_UNFAIR_LOCK 2
#define UL_COMPARE_AND_WAIT_SHARED 3
#define UL_UNFAIR_LOCK64_SHARED 4
#define UL_COMPARE_AND_WAIT64 5
#define UL_COMPARE_AND_WAIT64_SHARED 6
#define ULF_WAKE_ALL 0x00000100
#define ULF_WAKE_THREAD 0x00000200
#define ULF_WAKE_ALLOW_NON_OWNER 0x00000400
#define ULF_WAIT_WORKQ_DATA_CONTENTION 0x00010000
#define ULF_WAIT_CANCEL_POINT 0x00020000
#define ULF_WAIT_ADAPTIVE_SPIN 0x00040000
#define ULF_NO_ERRNO 0x01000000
#define UL_OPCODE_MASK 0x000000FF
#define UL_FLAGS_MASK 0xFFFFFF00
#define ULF_GENERIC_MASK 0xFFFF0000
extern int __ulock_wait(uint32_t operation, void *addr, uint64_t value,
uint32_t timeout);
extern int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
std::errc shared_atomic32::wait_impl(std::uint32_t oldValue,
std::chrono::microseconds usec_timeout) {
int result = __ulock_wait(UL_COMPARE_AND_WAIT_SHARED, (void *)this, oldValue,
usec_timeout.count());
if (result < 0) {
return static_cast<std::errc>(errno);
}
return {};
}
int shared_atomic32::notify_n(int count) const {
int result = 0;
uint32_t operation = UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO;
if (count == 1) {
result = __ulock_wake(operation, (void *)this, 0);
} else if (count == std::numeric_limits<int>::max()) {
result = __ulock_wake(ULF_WAKE_ALL | operation, (void *)this, 0);
} else {
for (int i = 0; i < count; ++i) {
auto ret = __ulock_wake(operation, (void *)this, 0);
if (ret != 0) {
if (result == 0) {
result = ret;
}
break;
}
result++;
}
}
return result;
}
#else
#error Unimplemented atomic for this platform
#endif

View file

@ -0,0 +1,158 @@
#include "orbis/utils/SharedCV.hpp"
#include <chrono>
#ifdef ORBIS_HAS_FUTEX
#include <linux/futex.h>
#include <syscall.h>
#include <unistd.h>
#endif
namespace orbis::utils {
std::errc shared_cv::impl_wait(shared_mutex &mutex, unsigned _val,
std::uint64_t usec_timeout) noexcept {
// Not supposed to fail
if (!_val) {
std::abort();
}
std::errc result = {};
bool useTimeout = usec_timeout != static_cast<std::uint64_t>(-1);
while (true) {
result =
m_value.wait(_val, useTimeout ? std::chrono::microseconds(usec_timeout)
: std::chrono::microseconds::max());
bool spurious = result == std::errc::resource_unavailable_try_again;
// Cleanup
const auto old = m_value.fetch_op([&](unsigned &value) {
// Remove waiter if no signals
if ((value & ~c_waiter_mask) == 0) {
if (!spurious) {
value -= 1;
}
}
// Try to remove signal
if (value & c_signal_mask) {
value -= c_signal_one;
}
#ifdef ORBIS_HAS_FUTEX
if (value & c_locked_mask) {
value -= c_locked_mask;
}
#endif
});
#ifdef ORBIS_HAS_FUTEX
// Lock is already acquired
if (old & c_locked_mask) {
return {};
}
// Wait directly (waiter has been added)
if (old & c_signal_mask) {
return mutex.impl_wait();
}
#else
if (old & c_signal_mask) {
result = {};
break;
}
#endif
// Possibly spurious wakeup
if (!spurious) {
break;
}
_val = old;
}
mutex.lock();
return result;
}
void shared_cv::impl_wake(shared_mutex &mutex, int _count) noexcept {
#ifdef ORBIS_HAS_FUTEX
while (true) {
unsigned _old = m_value.load();
const bool is_one = _count == 1;
// Enqueue _count waiters
_count = std::min<int>(_count, _old & c_waiter_mask);
if (_count <= 0)
return;
// Try to lock the mutex
const bool locked = mutex.lock_forced(_count);
const int max_sig = m_value.op([&](unsigned &value) {
// Verify the number of waiters
int max_sig = std::min<int>(_count, value & c_waiter_mask);
// Add lock signal (mutex was immediately locked)
if (locked && max_sig)
value |= c_locked_mask;
else if (locked)
std::abort();
// Add normal signals
value += c_signal_one * max_sig;
// Remove waiters
value -= max_sig;
_old = value;
return max_sig;
});
if (max_sig < _count) {
// Fixup mutex
mutex.lock_forced(max_sig - _count);
_count = max_sig;
}
if (_count) {
// Wake up one thread + requeue remaining waiters
unsigned awake_count = locked ? 1 : 0;
if (auto r = syscall(SYS_futex, &m_value, FUTEX_REQUEUE, awake_count,
_count - awake_count, &mutex, 0);
r < _count) {
// Keep awaking waiters
_count = is_one ? 1 : INT_MAX;
continue;
}
}
break;
}
#else
unsigned _old = m_value.load();
_count = std::min<int>(_count, _old & c_waiter_mask);
if (_count <= 0)
return;
mutex.lock_forced(1);
const int wakeupWaiters = m_value.op([&](unsigned &value) {
int max_sig = std::min<int>(_count, value & c_waiter_mask);
// Add normal signals
value += c_signal_one * max_sig;
// Remove waiters
value -= max_sig;
_old = value;
return max_sig;
});
if (wakeupWaiters > 0) {
m_value.notify_n(wakeupWaiters);
}
mutex.unlock();
#endif
}
} // namespace orbis::utils

View file

@ -0,0 +1,182 @@
#include "utils/SharedMutex.hpp"
#include "utils/Logs.hpp"
#include <syscall.h>
#include <unistd.h>
#include <xmmintrin.h>
static void busy_wait(unsigned long long cycles = 3000) {
const auto stop = __builtin_ia32_rdtsc() + cycles;
do
_mm_pause();
while (__builtin_ia32_rdtsc() < stop);
}
namespace orbis::utils {
void shared_mutex::impl_lock_shared(unsigned val) {
if (val >= c_err)
std::abort(); // "shared_mutex underflow"
// Try to steal the notification bit
unsigned _old = val;
if (val & c_sig && m_value.compare_exchange_strong(_old, val - c_sig + 1)) {
return;
}
for (int i = 0; i < 10; i++) {
if (try_lock_shared()) {
return;
}
unsigned old = m_value;
if (old & c_sig && m_value.compare_exchange_strong(old, old - c_sig + 1)) {
return;
}
busy_wait();
}
// Acquire writer lock and downgrade
const unsigned old = m_value.fetch_add(c_one);
if (old == 0) {
lock_downgrade();
return;
}
if ((old % c_sig) + c_one >= c_sig)
std::abort(); // "shared_mutex overflow"
while (impl_wait() != std::errc{}) {
}
lock_downgrade();
}
void shared_mutex::impl_unlock_shared(unsigned old) {
if (old - 1 >= c_err)
std::abort(); // "shared_mutex underflow"
// Check reader count, notify the writer if necessary
if ((old - 1) % c_one == 0) {
impl_signal();
}
}
std::errc shared_mutex::impl_wait() {
while (true) {
const auto [old, ok] = m_value.fetch_op([](unsigned &value) {
if (value >= c_sig) {
value -= c_sig;
return true;
}
return false;
});
if (ok) {
break;
}
auto result = m_value.wait(old);
if (result == std::errc::interrupted) {
return result;
}
}
return {};
}
void shared_mutex::impl_signal() {
m_value += c_sig;
m_value.notify_one();
}
void shared_mutex::impl_lock(unsigned val) {
if (val >= c_err)
std::abort(); // "shared_mutex underflow"
// Try to steal the notification bit
unsigned _old = val;
if (val & c_sig &&
m_value.compare_exchange_strong(_old, val - c_sig + c_one)) {
return;
}
for (int i = 0; i < 10; i++) {
busy_wait();
unsigned old = m_value;
if (!old && try_lock()) {
return;
}
if (old & c_sig &&
m_value.compare_exchange_strong(old, old - c_sig + c_one)) {
return;
}
}
const unsigned old = m_value.fetch_add(c_one);
if (old == 0) {
return;
}
if ((old % c_sig) + c_one >= c_sig)
std::abort(); // "shared_mutex overflow"
while (impl_wait() != std::errc{}) {
}
}
void shared_mutex::impl_unlock(unsigned old) {
if (old - c_one >= c_err)
std::abort(); // "shared_mutex underflow"
// 1) Notify the next writer if necessary
// 2) Notify all readers otherwise if necessary (currently indistinguishable
// from writers)
if (old - c_one) {
impl_signal();
}
}
void shared_mutex::impl_lock_upgrade() {
for (int i = 0; i < 10; i++) {
busy_wait();
if (try_lock_upgrade()) {
return;
}
}
// Convert to writer lock
const unsigned old = m_value.fetch_add(c_one - 1);
if ((old % c_sig) + c_one - 1 >= c_sig)
std::abort(); // "shared_mutex overflow"
if (old % c_one == 1) {
return;
}
while (impl_wait() != std::errc{}) {
}
}
bool shared_mutex::lock_forced(int count) {
if (count == 0)
return false;
if (count > 0) {
// Lock
return m_value.op([&](std::uint32_t &v) {
if (v & c_sig) {
v -= c_sig;
v += c_one * count;
return true;
}
bool firstLock = v == 0;
v += c_one * count;
return firstLock;
});
}
// Remove waiters
m_value.fetch_add(c_one * count);
return true;
}
} // namespace orbis::utils