mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-20 22:05:12 +00:00
move orbis-kernel to kernel/orbis
This commit is contained in:
parent
7419457efd
commit
ecaf607a8f
120 changed files with 1 additions and 1 deletions
420
kernel/orbis/src/KernelContext.cpp
Normal file
420
kernel/orbis/src/KernelContext.cpp
Normal 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
103
kernel/orbis/src/event.cpp
Normal 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
157
kernel/orbis/src/evf.cpp
Normal 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
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
415
kernel/orbis/src/module.cpp
Normal 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
95
kernel/orbis/src/pipe.cpp
Normal 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};
|
||||
}
|
||||
6
kernel/orbis/src/sys/sys_acct.cpp
Normal file
6
kernel/orbis/src/sys/sys_acct.cpp
Normal 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;
|
||||
}
|
||||
35
kernel/orbis/src/sys/sys_audit.cpp
Normal file
35
kernel/orbis/src/sys/sys_audit.cpp
Normal 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;
|
||||
}
|
||||
15
kernel/orbis/src/sys/sys_capability.cpp
Normal file
15
kernel/orbis/src/sys/sys_capability.cpp
Normal 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;
|
||||
}
|
||||
12
kernel/orbis/src/sys/sys_context.cpp
Normal file
12
kernel/orbis/src/sys/sys_context.cpp
Normal 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;
|
||||
}
|
||||
195
kernel/orbis/src/sys/sys_cpuset.cpp
Normal file
195
kernel/orbis/src/sys/sys_cpuset.cpp
Normal 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;
|
||||
}
|
||||
80
kernel/orbis/src/sys/sys_descrip.cpp
Normal file
80
kernel/orbis/src/sys/sys_descrip.cpp
Normal 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;
|
||||
}
|
||||
86
kernel/orbis/src/sys/sys_environment.cpp
Normal file
86
kernel/orbis/src/sys/sys_environment.cpp
Normal 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 {};
|
||||
}
|
||||
402
kernel/orbis/src/sys/sys_event.cpp
Normal file
402
kernel/orbis/src/sys/sys_event.cpp
Normal 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 ¬e = 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 ¬e = *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 {};
|
||||
}
|
||||
23
kernel/orbis/src/sys/sys_exec.cpp
Normal file
23
kernel/orbis/src/sys/sys_exec.cpp
Normal 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;
|
||||
}
|
||||
59
kernel/orbis/src/sys/sys_exit.cpp
Normal file
59
kernel/orbis/src/sys/sys_exit.cpp
Normal 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 {};
|
||||
}
|
||||
24
kernel/orbis/src/sys/sys_fork.cpp
Normal file
24
kernel/orbis/src/sys/sys_fork.cpp
Normal 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;
|
||||
}
|
||||
507
kernel/orbis/src/sys/sys_generic.cpp
Normal file
507
kernel/orbis/src/sys/sys_generic.cpp
Normal 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;
|
||||
}
|
||||
19
kernel/orbis/src/sys/sys_jail.cpp
Normal file
19
kernel/orbis/src/sys/sys_jail.cpp
Normal 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;
|
||||
}
|
||||
10
kernel/orbis/src/sys/sys_ktrace.cpp
Normal file
10
kernel/orbis/src/sys/sys_ktrace.cpp
Normal 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;
|
||||
}
|
||||
29
kernel/orbis/src/sys/sys_linker.cpp
Normal file
29
kernel/orbis/src/sys/sys_linker.cpp
Normal 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;
|
||||
}
|
||||
9
kernel/orbis/src/sys/sys_loginclass.cpp
Normal file
9
kernel/orbis/src/sys/sys_loginclass.cpp
Normal 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;
|
||||
}
|
||||
44
kernel/orbis/src/sys/sys_mac.cpp
Normal file
44
kernel/orbis/src/sys/sys_mac.cpp
Normal 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;
|
||||
}
|
||||
15
kernel/orbis/src/sys/sys_module.cpp
Normal file
15
kernel/orbis/src/sys/sys_module.cpp
Normal 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;
|
||||
}
|
||||
22
kernel/orbis/src/sys/sys_msg.cpp
Normal file
22
kernel/orbis/src/sys/sys_msg.cpp
Normal 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;
|
||||
}
|
||||
13
kernel/orbis/src/sys/sys_ntptime.cpp
Normal file
13
kernel/orbis/src/sys/sys_ntptime.cpp
Normal 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;
|
||||
}
|
||||
42
kernel/orbis/src/sys/sys_p1003_1b.cpp
Normal file
42
kernel/orbis/src/sys/sys_p1003_1b.cpp
Normal 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;
|
||||
}
|
||||
15
kernel/orbis/src/sys/sys_pipe.cpp
Normal file
15
kernel/orbis/src/sys/sys_pipe.cpp
Normal 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 {};
|
||||
}
|
||||
5
kernel/orbis/src/sys/sys_procdesc.cpp
Normal file
5
kernel/orbis/src/sys/sys_procdesc.cpp
Normal 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;
|
||||
}
|
||||
6
kernel/orbis/src/sys/sys_process.cpp
Normal file
6
kernel/orbis/src/sys/sys_process.cpp
Normal 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;
|
||||
}
|
||||
90
kernel/orbis/src/sys/sys_prot.cpp
Normal file
90
kernel/orbis/src/sys/sys_prot.cpp
Normal 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 {};
|
||||
}
|
||||
5
kernel/orbis/src/sys/sys_pty_pts.cpp
Normal file
5
kernel/orbis/src/sys/sys_pty_pts.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
|
||||
orbis::SysResult orbis::sys_posix_openpt(Thread *thread, sint flags) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
32
kernel/orbis/src/sys/sys_rctl.cpp
Normal file
32
kernel/orbis/src/sys/sys_rctl.cpp
Normal 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;
|
||||
}
|
||||
140
kernel/orbis/src/sys/sys_resource.cpp
Normal file
140
kernel/orbis/src/sys/sys_resource.cpp
Normal 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 {};
|
||||
}
|
||||
5
kernel/orbis/src/sys/sys_route.cpp
Normal file
5
kernel/orbis/src/sys/sys_route.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
|
||||
orbis::SysResult orbis::sys_setfib(Thread *thread, sint fib) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
1943
kernel/orbis/src/sys/sys_sce.cpp
Normal file
1943
kernel/orbis/src/sys/sys_sce.cpp
Normal file
File diff suppressed because it is too large
Load diff
18
kernel/orbis/src/sys/sys_sem.cpp
Normal file
18
kernel/orbis/src/sys/sys_sem.cpp
Normal 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;
|
||||
}
|
||||
21
kernel/orbis/src/sys/sys_shm.cpp
Normal file
21
kernel/orbis/src/sys/sys_shm.cpp
Normal 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;
|
||||
}
|
||||
5
kernel/orbis/src/sys/sys_shutdown.cpp
Normal file
5
kernel/orbis/src/sys/sys_shutdown.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
|
||||
orbis::SysResult orbis::sys_reboot(Thread *thread, sint opt) {
|
||||
return ErrorCode::NOSYS;
|
||||
}
|
||||
153
kernel/orbis/src/sys/sys_sig.cpp
Normal file
153
kernel/orbis/src/sys/sys_sig.cpp
Normal 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 {};
|
||||
}
|
||||
6
kernel/orbis/src/sys/sys_subr_prof.cpp
Normal file
6
kernel/orbis/src/sys/sys_subr_prof.cpp
Normal 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;
|
||||
}
|
||||
8
kernel/orbis/src/sys/sys_swap_pager.cpp
Normal file
8
kernel/orbis/src/sys/sys_swap_pager.cpp
Normal 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;
|
||||
}
|
||||
7
kernel/orbis/src/sys/sys_synch.cpp
Normal file
7
kernel/orbis/src/sys/sys_synch.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include "sys/sysproto.hpp"
|
||||
#include <thread>
|
||||
|
||||
orbis::SysResult orbis::sys_yield(Thread *thread) {
|
||||
std::this_thread::yield();
|
||||
return {};
|
||||
}
|
||||
1021
kernel/orbis/src/sys/sys_sysctl.cpp
Normal file
1021
kernel/orbis/src/sys/sys_sysctl.cpp
Normal file
File diff suppressed because it is too large
Load diff
77
kernel/orbis/src/sys/sys_thr.cpp
Normal file
77
kernel/orbis/src/sys/sys_thr.cpp
Normal 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;
|
||||
}
|
||||
199
kernel/orbis/src/sys/sys_time.cpp
Normal file
199
kernel/orbis/src/sys/sys_time.cpp
Normal 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;
|
||||
}
|
||||
229
kernel/orbis/src/sys/sys_uipc.cpp
Normal file
229
kernel/orbis/src/sys/sys_uipc.cpp
Normal 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;
|
||||
}
|
||||
31
kernel/orbis/src/sys/sys_uipc_mqueue.cpp
Normal file
31
kernel/orbis/src/sys/sys_uipc_mqueue.cpp
Normal 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;
|
||||
}
|
||||
37
kernel/orbis/src/sys/sys_uipc_sem.cpp
Normal file
37
kernel/orbis/src/sys/sys_uipc_sem.cpp
Normal 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;
|
||||
}
|
||||
45
kernel/orbis/src/sys/sys_uipc_shm.cpp
Normal file
45
kernel/orbis/src/sys/sys_uipc_shm.cpp
Normal 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;
|
||||
}
|
||||
177
kernel/orbis/src/sys/sys_umtx.cpp
Normal file
177
kernel/orbis/src/sys/sys_umtx.cpp
Normal 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;
|
||||
}
|
||||
6
kernel/orbis/src/sys/sys_uuid.cpp
Normal file
6
kernel/orbis/src/sys/sys_uuid.cpp
Normal 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;
|
||||
}
|
||||
498
kernel/orbis/src/sys/sys_vfs.cpp
Normal file
498
kernel/orbis/src/sys/sys_vfs.cpp
Normal 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;
|
||||
}
|
||||
61
kernel/orbis/src/sys/sys_vfs_acl.cpp
Normal file
61
kernel/orbis/src/sys/sys_vfs_acl.cpp
Normal 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;
|
||||
}
|
||||
53
kernel/orbis/src/sys/sys_vfs_aio.cpp
Normal file
53
kernel/orbis/src/sys/sys_vfs_aio.cpp
Normal 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;
|
||||
}
|
||||
23
kernel/orbis/src/sys/sys_vfs_cache.cpp
Normal file
23
kernel/orbis/src/sys/sys_vfs_cache.cpp
Normal 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 {};
|
||||
}
|
||||
79
kernel/orbis/src/sys/sys_vfs_extattr.cpp
Normal file
79
kernel/orbis/src/sys/sys_vfs_extattr.cpp
Normal 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;
|
||||
}
|
||||
27
kernel/orbis/src/sys/sys_vfs_mount.cpp
Normal file
27
kernel/orbis/src/sys/sys_vfs_mount.cpp
Normal 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;
|
||||
}
|
||||
104
kernel/orbis/src/sys/sys_vm_mmap.cpp
Normal file
104
kernel/orbis/src/sys/sys_vm_mmap.cpp
Normal 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;
|
||||
}
|
||||
8
kernel/orbis/src/sys/sys_vm_unix.cpp
Normal file
8
kernel/orbis/src/sys/sys_vm_unix.cpp
Normal 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
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
891
kernel/orbis/src/umtx.cpp
Normal 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 {};
|
||||
}
|
||||
545
kernel/orbis/src/utils/Logs.cpp
Normal file
545
kernel/orbis/src/utils/Logs.cpp
Normal 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
|
||||
118
kernel/orbis/src/utils/SharedAtomic.cpp
Normal file
118
kernel/orbis/src/utils/SharedAtomic.cpp
Normal 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
|
||||
158
kernel/orbis/src/utils/SharedCV.cpp
Normal file
158
kernel/orbis/src/utils/SharedCV.cpp
Normal 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
|
||||
182
kernel/orbis/src/utils/SharedMutex.cpp
Normal file
182
kernel/orbis/src/utils/SharedMutex.cpp
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue