Initial commit

This commit is contained in:
nmzik
2026-07-16 10:21:41 +02:00
commit 147188b143
427 changed files with 205923 additions and 0 deletions
+380
View File
@@ -0,0 +1,380 @@
#include "kernel/eventFlag.h"
#include "common/assert.h"
#include "common/common.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "common/timer.h"
#include "libs/errno.h"
#include "libs/libs.h"
namespace Libs::LibKernel::EventFlag {
LIB_NAME("libkernel", "libkernel");
class KernelEventFlagPrivate {
public:
enum class Result { Ok, AlreadyWaiting, TimedOut, Canceled, Deleted };
enum class ClearMode { None, All, Bits };
enum class WaitMode { And, Or };
KernelEventFlagPrivate(const std::string& name, bool single, bool /*fifo*/, uint64_t bits)
: m_name(name), m_single_thread(single), m_bits(bits) {}
virtual ~KernelEventFlagPrivate();
KYTY_CLASS_NO_COPY(KernelEventFlagPrivate);
void Set(uint64_t bits);
void Clear(uint64_t bits);
void Cancel(uint64_t bits, int* num_waiting_threads);
Result Wait(uint64_t bits, WaitMode wait_mode, ClearMode clear_mode, uint64_t* result,
uint32_t* ptr_micros);
Result Poll(uint64_t bits, WaitMode wait_mode, ClearMode clear_mode, uint64_t* result) {
uint32_t micros = 0;
return Wait(bits, wait_mode, clear_mode, result, &micros);
}
private:
enum class Status { Set, Canceled, Deleted };
Common::Mutex m_mutex;
Common::CondVar m_cond_var;
Status m_status = Status::Set;
int m_waiting_threads = 0;
std::string m_name;
bool m_single_thread = false;
uint64_t m_bits = 0;
};
namespace {
struct EventFlagWaitMode {
KernelEventFlagPrivate::WaitMode wait = KernelEventFlagPrivate::WaitMode::And;
KernelEventFlagPrivate::ClearMode clear = KernelEventFlagPrivate::ClearMode::None;
};
EventFlagWaitMode DecodeEventFlagWaitMode(uint32_t wait_mode) {
EventFlagWaitMode mode;
switch (wait_mode & 0xfu) {
case 0x01: mode.wait = KernelEventFlagPrivate::WaitMode::And; break;
case 0x02: mode.wait = KernelEventFlagPrivate::WaitMode::Or; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
switch (wait_mode & 0xf0u) {
case 0x00: mode.clear = KernelEventFlagPrivate::ClearMode::None; break;
case 0x10: mode.clear = KernelEventFlagPrivate::ClearMode::All; break;
case 0x20: mode.clear = KernelEventFlagPrivate::ClearMode::Bits; break;
default: EXIT("unknown mode: %u\n", wait_mode);
}
return mode;
}
} // namespace
KernelEventFlagPrivate::~KernelEventFlagPrivate() {
Common::LockGuard lock(m_mutex);
while (m_status != Status::Set) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_status = Status::Deleted;
m_cond_var.SignalAll();
while (m_waiting_threads > 0) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
}
KernelEventFlagPrivate::Result KernelEventFlagPrivate::Wait(uint64_t bits, WaitMode wait_mode,
ClearMode clear_mode, uint64_t* result,
uint32_t* ptr_micros) {
Common::LockGuard lock(m_mutex);
uint32_t micros = 0;
bool infinitely = true;
if (ptr_micros != nullptr) {
micros = *ptr_micros;
infinitely = false;
}
uint32_t elapsed = 0;
Common::Timer t;
t.Start();
auto update_timeout = [&]() {
if (ptr_micros != nullptr) {
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
};
if (m_single_thread && m_waiting_threads > 0) {
return Result::AlreadyWaiting;
}
while (!((wait_mode == WaitMode::And && (m_bits & bits) == bits) ||
(wait_mode == WaitMode::Or && (m_bits & bits) != 0))) {
if ((elapsed >= micros && !infinitely)) {
if (result != nullptr) {
*result = m_bits;
}
update_timeout();
return Result::TimedOut;
}
m_waiting_threads++;
if (infinitely) {
m_cond_var.Wait(&m_mutex);
} else {
m_cond_var.WaitFor(&m_mutex, micros - elapsed);
}
m_waiting_threads--;
elapsed = static_cast<uint32_t>(t.GetTimeS() * 1000000.0);
switch (m_status) {
case Status::Canceled:
if (result != nullptr) {
*result = m_bits;
}
update_timeout();
return Result::Canceled;
case Status::Deleted:
if (result != nullptr) {
*result = m_bits;
}
update_timeout();
return Result::Deleted;
case Status::Set: break;
}
}
if (result != nullptr) {
*result = m_bits;
}
update_timeout();
switch (clear_mode) {
case ClearMode::All: m_bits = 0; break;
case ClearMode::Bits: m_bits &= ~bits; break;
case ClearMode::None: break;
}
return Result::Ok;
}
void KernelEventFlagPrivate::Set(uint64_t bits) {
Common::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_bits |= bits;
m_cond_var.SignalAll();
}
void KernelEventFlagPrivate::Clear(uint64_t bits) {
Common::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_bits &= bits;
}
void KernelEventFlagPrivate::Cancel(uint64_t bits, int* num_waiting_threads) {
Common::LockGuard lock(m_mutex);
EXIT_NOT_IMPLEMENTED(m_status == Status::Deleted);
while (m_status != Status::Set) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
if (num_waiting_threads != nullptr) {
*num_waiting_threads = m_waiting_threads;
}
m_status = Status::Canceled;
m_bits = bits;
m_cond_var.SignalAll();
while (m_waiting_threads > 0) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_status = Status::Set;
}
int KYTY_SYSV_ABI KernelCreateEventFlag(KernelEventFlag* ef, const char* name, uint32_t attr,
uint64_t init_pattern, const void* param) {
PRINT_NAME();
if (ef == nullptr || name == nullptr) {
return KERNEL_ERROR_EINVAL;
}
if (param != nullptr || (attr & ~0x33u) != 0) {
return KERNEL_ERROR_EINVAL;
}
bool single = true;
bool fifo = true;
switch (attr & 0x0fu) {
case 0x00:
case 0x01: fifo = true; break;
case 0x02: fifo = false; break;
default: return KERNEL_ERROR_EINVAL;
}
switch (attr & 0xf0u) {
case 0x00:
case 0x10: single = true; break;
case 0x20: single = false; break;
default: return KERNEL_ERROR_EINVAL;
}
*ef = new KernelEventFlagPrivate(std::string(name), single, fifo, init_pattern);
LOGF("\tEventFlag create: %s\n", name);
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEventFlag(KernelEventFlag ef) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
delete ef;
return OK;
}
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
uint64_t* result_pat, KernelUseconds* timeout) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
if (bit_pattern == 0) {
return KERNEL_ERROR_EINVAL;
}
const auto mode = DecodeEventFlagWaitMode(wait_mode);
auto result = ef->Wait(bit_pattern, mode.wait, mode.clear, result_pat, timeout);
int ret = OK;
switch (result) {
case KernelEventFlagPrivate::Result::Ok: ret = OK; break;
case KernelEventFlagPrivate::Result::AlreadyWaiting: ret = KERNEL_ERROR_EPERM; break;
case KernelEventFlagPrivate::Result::TimedOut: ret = KERNEL_ERROR_ETIMEDOUT; break;
case KernelEventFlagPrivate::Result::Canceled: ret = KERNEL_ERROR_ECANCELED; break;
case KernelEventFlagPrivate::Result::Deleted: ret = KERNEL_ERROR_EACCES; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelPollEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
uint64_t* result_pat) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
if (bit_pattern == 0) {
return KERNEL_ERROR_EINVAL;
}
const auto mode = DecodeEventFlagWaitMode(wait_mode);
auto result = ef->Poll(bit_pattern, mode.wait, mode.clear, result_pat);
int ret = OK;
switch (result) {
case KernelEventFlagPrivate::Result::Ok: ret = OK; break;
case KernelEventFlagPrivate::Result::AlreadyWaiting: ret = KERNEL_ERROR_EPERM; break;
case KernelEventFlagPrivate::Result::TimedOut:
case KernelEventFlagPrivate::Result::Canceled:
case KernelEventFlagPrivate::Result::Deleted: ret = KERNEL_ERROR_EBUSY; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelSetEventFlag(KernelEventFlag ef, uint64_t bit_pattern) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
ef->Set(bit_pattern);
return OK;
}
int KYTY_SYSV_ABI KernelClearEventFlag(KernelEventFlag ef, uint64_t bit_pattern) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
ef->Clear(bit_pattern);
return OK;
}
int KYTY_SYSV_ABI KernelCancelEventFlag(KernelEventFlag ef, uint64_t set_pattern,
int* num_wait_threads) {
PRINT_NAME();
if (ef == nullptr) {
return KERNEL_ERROR_ESRCH;
}
ef->Cancel(set_pattern, num_wait_threads);
return OK;
}
} // namespace Libs::LibKernel::EventFlag
+28
View File
@@ -0,0 +1,28 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_
#include "common/abi.h"
#include "common/common.h"
#include "kernel/pthread.h"
namespace Libs::LibKernel::EventFlag {
class KernelEventFlagPrivate;
using KernelEventFlag = KernelEventFlagPrivate*;
int KYTY_SYSV_ABI KernelCreateEventFlag(KernelEventFlag* ef, const char* name, uint32_t attr,
uint64_t init_pattern, const void* param);
int KYTY_SYSV_ABI KernelDeleteEventFlag(KernelEventFlag ef);
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
uint64_t* result_pat, KernelUseconds* timeout);
int KYTY_SYSV_ABI KernelPollEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
uint64_t* result_pat);
int KYTY_SYSV_ABI KernelSetEventFlag(KernelEventFlag ef, uint64_t bit_pattern);
int KYTY_SYSV_ABI KernelClearEventFlag(KernelEventFlag ef, uint64_t bit_pattern);
int KYTY_SYSV_ABI KernelCancelEventFlag(KernelEventFlag ef, uint64_t set_pattern,
int* num_wait_threads);
} // namespace Libs::LibKernel::EventFlag
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTFLAG_H_ */
+621
View File
@@ -0,0 +1,621 @@
#include "kernel/eventQueue.h"
#include "common/assert.h"
#include "common/common.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "common/timer.h"
#include "libs/errno.h"
#include "libs/libs.h"
#include <algorithm>
#include <chrono>
#include <fmt/format.h>
#include <list>
namespace Libs::LibKernel::EventQueue {
LIB_NAME("libkernel", "libkernel");
constexpr uint16_t EV_ADD = 0x01;
constexpr uint16_t EV_ONESHOT = 0x10;
constexpr uint16_t EV_CLEAR = 0x20;
constexpr uint16_t EV_ERROR = 0x4000;
static uint64_t MonotonicTimeNs() {
return static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now().time_since_epoch())
.count());
}
static std::list<KernelEqueue> g_equeues;
static Common::Mutex g_equeues_mutex;
class KernelEqueuePrivate {
public:
KernelEqueuePrivate() = default;
virtual ~KernelEqueuePrivate();
KYTY_CLASS_NO_COPY(KernelEqueuePrivate);
[[nodiscard]] const std::string& GetName() const { return m_name; }
void SetName(const std::string& m_name) { this->m_name = m_name; }
void AddEvent(const KernelEqueueEvent& event);
bool TriggerEvent(uintptr_t ident, int16_t filter, void* trigger_data);
bool DeleteEvent(uintptr_t ident, int16_t filter);
int GetTriggeredEvents(KernelEvent* ev, int num);
int WaitForEvents(KernelEvent* ev, int num, uint32_t micros);
private:
void TriggerExpiredTimers(uint64_t now_ns);
bool GetNextTimerWaitMicros(uint64_t now_ns, uint32_t* wait_micros) const;
std::list<KernelEqueueEvent> m_events;
Common::Mutex m_mutex;
Common::CondVar m_cond_var;
std::string m_name;
};
KernelEqueuePrivate::~KernelEqueuePrivate() {
Common::LockGuard lock(m_mutex);
for (auto& event: m_events) {
if (event.filter.delete_event_func != nullptr) {
event.filter.delete_event_func(this, &event);
}
}
}
int KernelEqueuePrivate::GetTriggeredEvents(KernelEvent* ev, int num) {
Common::LockGuard lock(m_mutex);
EXIT_IF(num < 1);
TriggerExpiredTimers(MonotonicTimeNs());
int ret = 0;
for (auto it = m_events.begin(); it != m_events.end();) {
auto& event = *it;
bool erase = false;
while (event.triggered) {
ev[ret++] = event.event;
if ((event.event.flags & EV_ONESHOT) != 0) {
erase = true;
break;
}
if (event.filter.reset_func != nullptr) {
event.filter.reset_func(&event);
} else if ((event.event.flags & EV_CLEAR) != 0) {
event.triggered = false;
event.event.fflags = 0;
event.event.data = 0;
}
if (!event.pending_events.empty()) {
event.event = event.pending_events.front();
event.pending_events.pop_front();
event.triggered = true;
}
if (ret >= num) {
break;
}
}
it = (erase ? m_events.erase(it) : std::next(it));
if (ret >= num) {
break;
}
}
return ret;
}
void KernelEqueuePrivate::TriggerExpiredTimers(uint64_t now_ns) {
for (auto& event: m_events) {
if (!event.triggered && event.deadline_ns != 0 && event.deadline_ns <= now_ns) {
event.triggered = true;
}
}
}
bool KernelEqueuePrivate::GetNextTimerWaitMicros(uint64_t now_ns, uint32_t* wait_micros) const {
EXIT_IF(wait_micros == nullptr);
uint64_t nearest_deadline = UINT64_MAX;
for (const auto& event: m_events) {
if (!event.triggered && event.deadline_ns != 0) {
nearest_deadline = std::min(nearest_deadline, event.deadline_ns);
}
}
if (nearest_deadline == UINT64_MAX) {
return false;
}
const auto remaining_ns = nearest_deadline > now_ns ? nearest_deadline - now_ns : 0;
const auto rounded_us = std::max<uint64_t>(1, (remaining_ns + 999u) / 1000u);
*wait_micros = static_cast<uint32_t>(std::min<uint64_t>(rounded_us, UINT32_MAX));
return true;
}
int KernelEqueuePrivate::WaitForEvents(KernelEvent* ev, int num, uint32_t micros) {
Common::LockGuard lock(m_mutex);
EXIT_IF(num < 1);
uint32_t elapsed = 0;
Common::Timer t;
t.Start();
for (;;) {
int ret = GetTriggeredEvents(ev, num);
if (ret > 0 || (elapsed >= micros && micros != 0)) {
return ret;
}
uint32_t timer_wait = 0;
const bool has_timer = GetNextTimerWaitMicros(MonotonicTimeNs(), &timer_wait);
if (micros == 0 && !has_timer) {
m_cond_var.Wait(&m_mutex);
} else {
const auto external_wait = micros != 0 ? micros - elapsed : UINT32_MAX;
m_cond_var.WaitFor(&m_mutex,
has_timer ? std::min(external_wait, timer_wait) : external_wait);
}
elapsed = static_cast<uint32_t>(t.GetTimeS() * 1000000.0);
}
return 0;
}
void KernelEqueuePrivate::AddEvent(const KernelEqueueEvent& event) {
Common::LockGuard lock(m_mutex);
auto it = std::find_if(m_events.begin(), m_events.end(),
[ident = event.event.ident, filter = event.event.filter](const auto& e) {
return e.event.ident == ident && e.event.filter == filter;
});
if (it != m_events.end()) {
*it = event;
} else {
m_events.push_back(event);
}
m_cond_var.Signal();
}
bool KernelEqueuePrivate::TriggerEvent(uintptr_t ident, int16_t filter, void* trigger_data) {
Common::LockGuard lock(m_mutex);
auto it = std::find_if(m_events.begin(), m_events.end(), [ident, filter](const auto& e) {
return e.event.ident == ident && e.event.filter == filter;
});
if (it != m_events.end()) {
auto& event = *it;
if (event.filter.trigger_func != nullptr) {
event.filter.trigger_func(&event, trigger_data);
} else {
event.triggered = true;
}
m_cond_var.Signal();
return true;
}
return false;
}
static void UserEventTriggerFunc(KernelEqueueEvent* event, void* trigger_data) {
EXIT_IF(event == nullptr);
event->triggered = true;
event->event.data = reinterpret_cast<intptr_t>(trigger_data);
event->event.udata = trigger_data;
}
static void AmprEventTriggerFunc(KernelEqueueEvent* event, void* trigger_data) {
EXIT_IF(event == nullptr);
auto triggered_event = event->event;
triggered_event.data = static_cast<intptr_t>(reinterpret_cast<uintptr_t>(trigger_data));
if (event->triggered) {
event->pending_events.push_back(triggered_event);
} else {
event->event = triggered_event;
event->triggered = true;
}
}
static void UserEventResetFunc(KernelEqueueEvent* event) {
EXIT_IF(event == nullptr);
if ((event->event.flags & EV_CLEAR) != 0) {
event->triggered = false;
event->event.fflags = 0;
event->event.data = 0;
}
}
bool KernelEqueuePrivate::DeleteEvent(uintptr_t ident, int16_t filter) {
Common::LockGuard lock(m_mutex);
auto it = std::find_if(m_events.begin(), m_events.end(), [ident, filter](const auto& e) {
return e.event.ident == ident && e.event.filter == filter;
});
if (it != m_events.end()) {
auto& event = *it;
if (event.filter.delete_event_func != nullptr) {
event.filter.delete_event_func(this, &event);
}
m_events.erase(it);
return true;
}
return false;
}
int KYTY_SYSV_ABI KernelCreateEqueue(KernelEqueue* eq, const char* name) {
PRINT_NAME();
if (eq == nullptr || name == nullptr) {
return KERNEL_ERROR_EINVAL;
}
*eq = new KernelEqueuePrivate;
(*eq)->SetName(std::string(name));
{
Common::LockGuard lock(g_equeues_mutex);
g_equeues.push_back(*eq);
}
LOGF("\tEqueue create: %s\n", name);
return OK;
}
int KYTY_SYSV_ABI KernelAddEvent(KernelEqueue eq, const KernelEqueueEvent& event) {
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
eq->AddEvent(event);
return OK;
}
int KYTY_SYSV_ABI KernelTriggerEvent(KernelEqueue eq, uintptr_t ident, int16_t filter,
void* trigger_data) {
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
if (!eq->TriggerEvent(ident, filter, trigger_data)) {
return KERNEL_ERROR_ENOENT;
}
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEvent(KernelEqueue eq, uintptr_t ident, int16_t filter) {
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
if (!eq->DeleteEvent(ident, filter)) {
return KERNEL_ERROR_ENOENT;
}
return OK;
}
int KYTY_SYSV_ABI KernelDeleteEqueue(KernelEqueue eq) {
PRINT_NAME();
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
LOGF("\tEqueue delete: %s\n", eq->GetName().c_str());
{
Common::LockGuard lock(g_equeues_mutex);
g_equeues.remove(eq);
}
delete eq;
return OK;
}
int KYTY_SYSV_ABI KernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out,
const KernelUseconds* timo) {
PRINT_NAME();
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
if (ev == nullptr) {
return KERNEL_ERROR_EFAULT;
}
if (num < 1) {
return KERNEL_ERROR_EINVAL;
}
EXIT_NOT_IMPLEMENTED(out == nullptr);
LOGF("\tEqueue wait: %s, caller = 0x%016" PRIx64 ", eq = 0x%016" PRIx64 ", ev = 0x%016" PRIx64
", num = %d, timo = %s, thread_id = %d\n",
eq->GetName().c_str(), reinterpret_cast<uint64_t>(__builtin_return_address(0)),
reinterpret_cast<uint64_t>(eq), reinterpret_cast<uint64_t>(ev), num,
(timo == nullptr ? "inf" : fmt::format("{}", *timo).c_str()),
Common::Thread::GetThreadIdUnique());
if (timo == nullptr) {
*out = eq->WaitForEvents(ev, num, 0);
}
if (timo != nullptr) {
if (*timo == 0) {
*out = eq->GetTriggeredEvents(ev, num);
} else {
*out = eq->WaitForEvents(ev, num, *timo);
}
}
if (*out == 0) {
LOGF("\tEqueue wait timedout: %s\n", eq->GetName().c_str());
return KERNEL_ERROR_ETIMEDOUT;
}
LOGF("\tEqueue wait received %u events: ident = 0x%016" PRIx64
", filter = %d, flags = 0x%04" PRIx16 ", fflags = 0x%08" PRIx32 ", data = 0x%016" PRIx64
", udata = 0x%016" PRIx64 "\n",
*out, static_cast<uint64_t>(ev[0].ident), ev[0].filter, ev[0].flags, ev[0].fflags,
static_cast<uint64_t>(ev[0].data), reinterpret_cast<uint64_t>(ev[0].udata));
return OK;
}
int KYTY_SYSV_ABI KernelAddUserEvent(KernelEqueue eq, int id) {
PRINT_NAME();
LOGF("\t user event add: eq = 0x%016" PRIx64 ", id = %d\n", reinterpret_cast<uint64_t>(eq), id);
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
KernelEqueueEvent event {};
event.event.ident = static_cast<uintptr_t>(id);
event.event.filter = KERNEL_EVFILT_USER;
event.event.flags = EV_ADD;
event.event.fflags = 0;
event.event.data = 0;
event.event.udata = nullptr;
event.filter.trigger_func = UserEventTriggerFunc;
event.filter.reset_func = UserEventResetFunc;
eq->AddEvent(event);
return OK;
}
int KYTY_SYSV_ABI KernelAddUserEventEdge(KernelEqueue eq, int id) {
PRINT_NAME();
LOGF("\t user event edge add: eq = 0x%016" PRIx64 ", id = %d\n", reinterpret_cast<uint64_t>(eq),
id);
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
KernelEqueueEvent event {};
event.event.ident = static_cast<uintptr_t>(id);
event.event.filter = KERNEL_EVFILT_USER;
event.event.flags = EV_ADD | EV_CLEAR;
event.event.fflags = 0;
event.event.data = 0;
event.event.udata = nullptr;
event.filter.trigger_func = UserEventTriggerFunc;
event.filter.reset_func = UserEventResetFunc;
eq->AddEvent(event);
return OK;
}
int KYTY_SYSV_ABI KernelTriggerUserEvent(KernelEqueue eq, int id, void* udata) {
PRINT_NAME();
LOGF("\t user event trigger: eq = 0x%016" PRIx64 ", id = %d, udata = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(eq), id, reinterpret_cast<uint64_t>(udata));
return KernelTriggerEvent(eq, static_cast<uintptr_t>(id), KERNEL_EVFILT_USER, udata);
}
int KYTY_SYSV_ABI KernelTriggerUserEventForAll(int id, void* udata) {
int triggered = 0;
Common::LockGuard lock(g_equeues_mutex);
for (auto* eq: g_equeues) {
if (eq != nullptr &&
eq->TriggerEvent(static_cast<uintptr_t>(id), KERNEL_EVFILT_USER, udata)) {
triggered++;
}
}
return (triggered > 0 ? OK : KERNEL_ERROR_ENOENT);
}
int KYTY_SYSV_ABI KernelDeleteUserEvent(KernelEqueue eq, int id) {
PRINT_NAME();
LOGF("\t user event delete: eq = 0x%016" PRIx64 ", id = %d\n", reinterpret_cast<uint64_t>(eq),
id);
return KernelDeleteEvent(eq, static_cast<uintptr_t>(id), KERNEL_EVFILT_USER);
}
int KYTY_SYSV_ABI KernelAddHRTimerEvent(KernelEqueue eq, int id, const KernelTimespec* ts,
void* udata) {
if (eq == nullptr) {
return KERNEL_ERROR_EBADF;
}
if (ts == nullptr) {
return KERNEL_ERROR_EFAULT;
}
if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000ll ||
static_cast<uint64_t>(ts->tv_sec) >
(UINT64_MAX - static_cast<uint64_t>(ts->tv_nsec)) / 1000000000ull) {
return KERNEL_ERROR_EINVAL;
}
const auto delay_ns =
static_cast<uint64_t>(ts->tv_sec) * 1000000000ull + static_cast<uint64_t>(ts->tv_nsec);
const auto now_ns = MonotonicTimeNs();
KernelEqueueEvent event {};
event.deadline_ns = delay_ns <= UINT64_MAX - now_ns ? now_ns + delay_ns : UINT64_MAX;
event.event.ident = static_cast<uintptr_t>(id);
event.event.filter = KERNEL_EVFILT_HRTIMER;
event.event.flags = EV_ADD | EV_ONESHOT;
event.event.fflags = 0;
event.event.data = 0;
event.event.udata = udata;
eq->AddEvent(event);
return OK;
}
int KYTY_SYSV_ABI KernelDeleteHRTimerEvent(KernelEqueue eq, int id) {
return KernelDeleteEvent(eq, static_cast<uintptr_t>(id), KERNEL_EVFILT_HRTIMER);
}
int KYTY_SYSV_ABI KernelAddAmprEvent(KernelEqueue eq, int id, void* udata) {
PRINT_NAME();
LOGF("\t AMPR event add: eq = 0x%016" PRIx64 ", id = %d, udata = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(eq), id, reinterpret_cast<uint64_t>(udata));
if (eq != nullptr) {
KernelEqueueEvent event {};
event.event.ident = static_cast<uintptr_t>(id);
event.event.filter = KERNEL_EVFILT_USER;
event.event.flags = EV_ADD | EV_CLEAR;
event.event.fflags = 0;
event.event.data = 0;
event.event.udata = udata;
event.filter.trigger_func = AmprEventTriggerFunc;
event.filter.reset_func = UserEventResetFunc;
eq->AddEvent(event);
}
return OK;
}
int KYTY_SYSV_ABI KernelAddAmprSystemEvent(KernelEqueue eq, int id, void* udata) {
PRINT_NAME();
LOGF("\t AMPR system event add: eq = 0x%016" PRIx64 ", id = %d, udata = 0x%016" PRIx64 "\n",
reinterpret_cast<uint64_t>(eq), id, reinterpret_cast<uint64_t>(udata));
return KernelAddAmprEvent(eq, id, udata);
}
int KYTY_SYSV_ABI KernelDeleteAmprEvent(KernelEqueue eq, int id) {
PRINT_NAME();
LOGF("\t AMPR event delete: eq = 0x%016" PRIx64 ", id = %d\n", reinterpret_cast<uint64_t>(eq),
id);
if (eq != nullptr) {
eq->DeleteEvent(static_cast<uintptr_t>(id), KERNEL_EVFILT_USER);
}
return OK;
}
int KYTY_SYSV_ABI KernelDeleteAmprSystemEvent(KernelEqueue eq, int id) {
PRINT_NAME();
LOGF("\t AMPR system event delete: eq = 0x%016" PRIx64 ", id = %d\n",
reinterpret_cast<uint64_t>(eq), id);
return KernelDeleteAmprEvent(eq, id);
}
intptr_t KYTY_SYSV_ABI KernelGetEventData(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr) {
return ev->data;
}
return 0;
}
intptr_t KYTY_SYSV_ABI KernelGetEventFflags(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr) {
return ev->fflags;
}
return 0;
}
int KYTY_SYSV_ABI KernelGetEventFilter(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr) {
return ev->filter;
}
return 0;
}
uintptr_t KYTY_SYSV_ABI KernelGetEventId(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr) {
return ev->ident;
}
return 0;
}
void* KYTY_SYSV_ABI KernelGetEventUserData(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr) {
return ev->udata;
}
return nullptr;
}
int KYTY_SYSV_ABI KernelGetEventError(const KernelEvent* ev) {
PRINT_NAME();
if (ev != nullptr && (ev->flags & EV_ERROR) != 0) {
return static_cast<int>(ev->data);
}
return 0;
}
} // namespace Libs::LibKernel::EventQueue
+85
View File
@@ -0,0 +1,85 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_
#include "common/abi.h"
#include "common/common.h"
#include "kernel/pthread.h"
#include <deque>
namespace Libs::LibKernel::EventQueue {
constexpr int16_t KERNEL_EVFILT_TIMER = -7;
constexpr int16_t KERNEL_EVFILT_READ = -1;
constexpr int16_t KERNEL_EVFILT_WRITE = -2;
constexpr int16_t KERNEL_EVFILT_USER = -11;
constexpr int16_t KERNEL_EVFILT_FILE = -4;
constexpr int16_t KERNEL_EVFILT_GRAPHICS = -14;
constexpr int16_t KERNEL_EVFILT_VIDEO_OUT = -13;
constexpr int16_t KERNEL_EVFILT_HRTIMER = -15;
class KernelEqueuePrivate;
struct KernelEqueueEvent;
using KernelEqueue = KernelEqueuePrivate*;
using trigger_func_t = void (*)(KernelEqueueEvent* event, void* trigger_data);
using reset_func_t = void (*)(KernelEqueueEvent* event);
using delete_func_t = void (*)(KernelEqueue eq, KernelEqueueEvent* event);
struct KernelEvent {
uintptr_t ident = 0;
int16_t filter = 0;
uint16_t flags = 0;
uint32_t fflags = 0;
intptr_t data = 0;
void* udata = nullptr;
};
struct KernelFilter {
void* data = nullptr;
trigger_func_t trigger_func = nullptr;
reset_func_t reset_func = nullptr;
delete_func_t delete_event_func = nullptr;
};
struct KernelEqueueEvent {
bool triggered = false;
uint64_t deadline_ns = 0;
KernelEvent event;
KernelFilter filter;
std::deque<KernelEvent> pending_events;
};
int KYTY_SYSV_ABI KernelAddEvent(KernelEqueue eq, const KernelEqueueEvent& event);
int KYTY_SYSV_ABI KernelTriggerEvent(KernelEqueue eq, uintptr_t ident, int16_t filter,
void* trigger_data);
int KYTY_SYSV_ABI KernelDeleteEvent(KernelEqueue eq, uintptr_t ident, int16_t filter);
int KYTY_SYSV_ABI KernelCreateEqueue(KernelEqueue* eq, const char* name);
int KYTY_SYSV_ABI KernelDeleteEqueue(KernelEqueue eq);
int KYTY_SYSV_ABI KernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out,
const KernelUseconds* timo);
int KYTY_SYSV_ABI KernelAddUserEvent(KernelEqueue eq, int id);
int KYTY_SYSV_ABI KernelAddUserEventEdge(KernelEqueue eq, int id);
int KYTY_SYSV_ABI KernelTriggerUserEvent(KernelEqueue eq, int id, void* udata);
int KYTY_SYSV_ABI KernelTriggerUserEventForAll(int id, void* udata);
int KYTY_SYSV_ABI KernelDeleteUserEvent(KernelEqueue eq, int id);
int KYTY_SYSV_ABI KernelAddHRTimerEvent(KernelEqueue eq, int id, const KernelTimespec* ts,
void* udata);
int KYTY_SYSV_ABI KernelDeleteHRTimerEvent(KernelEqueue eq, int id);
int KYTY_SYSV_ABI KernelAddAmprEvent(KernelEqueue eq, int id, void* udata);
int KYTY_SYSV_ABI KernelAddAmprSystemEvent(KernelEqueue eq, int id, void* udata);
int KYTY_SYSV_ABI KernelDeleteAmprEvent(KernelEqueue eq, int id);
int KYTY_SYSV_ABI KernelDeleteAmprSystemEvent(KernelEqueue eq, int id);
intptr_t KYTY_SYSV_ABI KernelGetEventData(const KernelEvent* ev);
intptr_t KYTY_SYSV_ABI KernelGetEventFflags(const KernelEvent* ev);
int KYTY_SYSV_ABI KernelGetEventFilter(const KernelEvent* ev);
uintptr_t KYTY_SYSV_ABI KernelGetEventId(const KernelEvent* ev);
void* KYTY_SYSV_ABI KernelGetEventUserData(const KernelEvent* ev);
int KYTY_SYSV_ABI KernelGetEventError(const KernelEvent* ev);
} // namespace Libs::LibKernel::EventQueue
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_EVENTQUEUE_H_ */
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_
#include "common/abi.h"
#include "common/common.h"
#include "common/stringUtils.h"
#include "common/subsystems.h"
#include "kernel/pthread.h"
#include <filesystem>
namespace Libs::LibKernel::FileSystem {
struct FileStat {
uint32_t st_dev;
uint32_t st_ino;
uint16_t st_mode;
uint16_t st_nlink;
uint32_t st_uid;
uint32_t st_gid;
uint32_t st_rdev;
KernelTimespec st_atim;
KernelTimespec st_mtim;
KernelTimespec st_ctim;
int64_t st_size;
int64_t st_blocks;
uint32_t st_blksize;
uint32_t st_flags;
uint32_t st_gen;
int32_t st_lspare;
KernelTimespec st_birthtim;
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
unsigned int: (8 / 2) * (16 - static_cast<int>(sizeof(KernelTimespec)));
};
KYTY_SUBSYSTEM_DEFINE(FileSystem);
void Mount(const std::filesystem::path& folder, const std::string& point);
void Umount(const std::string& folder_or_point);
std::filesystem::path GetRealFilename(const std::string& mounted_file_name);
int KYTY_SYSV_ABI KernelOpen(const char* path, int flags, uint16_t mode);
int KYTY_SYSV_ABI KernelClose(int d);
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes);
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset);
int64_t KYTY_SYSV_ABI KernelWrite(int d, const void* buf, size_t nbytes);
int64_t KYTY_SYSV_ABI KernelPwrite(int d, const void* buf, size_t nbytes, int64_t offset);
int64_t KYTY_SYSV_ABI KernelLseek(int d, int64_t offset, int whence);
int KYTY_SYSV_ABI KernelStat(const char* path, FileStat* sb);
int KYTY_SYSV_ABI KernelFstat(int d, FileStat* sb);
int KYTY_SYSV_ABI KernelUnlink(const char* path);
int KYTY_SYSV_ABI KernelRename(const char* from, const char* to);
int KYTY_SYSV_ABI KernelGetdirentries(int fd, char* buf, int nbytes, int64_t* basep);
int KYTY_SYSV_ABI KernelGetdents(int fd, char* buf, int nbytes);
int KYTY_SYSV_ABI KernelMkdir(const char* path, uint16_t mode);
int KYTY_SYSV_ABI KernelRmdir(const char* path);
int KYTY_SYSV_ABI KernelCheckReachability(const char* path);
} // namespace Libs::LibKernel::FileSystem
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_FILESYSTEM_H_ */
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
#include "common/virtualMemory.h"
namespace Libs::LibKernel::Memory {
KYTY_SUBSYSTEM_DEFINE(Memory);
using callback_func_t = void (*)(uintptr_t addr, size_t size);
constexpr uint32_t KERNEL_MAXIMUM_NAME_LENGTH = 32;
struct VirtualQueryInfo {
uintptr_t start;
uintptr_t end;
uint64_t offset;
int32_t protection;
int32_t memory_type;
uint32_t is_flexible : 1;
uint32_t is_direct : 1;
uint32_t is_stack : 1;
uint32_t is_pooled : 1;
uint32_t is_committed : 1;
uint32_t is_gpu_prt : 1;
uint32_t amm_usage : 1;
uint32_t reserved : 1;
char name[KERNEL_MAXIMUM_NAME_LENGTH];
uint8_t gpu_mask_id;
uint8_t reserved2;
};
static_assert(sizeof(VirtualQueryInfo) == 72, "VirtualQueryInfo struct size is incorrect");
struct KernelBatchMapEntry {
void* start;
uint64_t offset;
uint64_t length;
char protection;
char type;
int16_t reserved;
int32_t operation;
};
static_assert(sizeof(KernelBatchMapEntry) == 32, "KernelBatchMapEntry struct size is incorrect");
struct KernelMemoryPoolBatchEntry {
uint32_t op;
uint32_t flags;
union {
struct {
void* addr;
uint64_t len;
uint8_t prot;
uint8_t type;
} commit;
struct {
void* addr;
uint64_t len;
} decommit;
struct {
void* addr;
uint64_t len;
uint8_t prot;
} protect;
struct {
void* addr;
uint64_t len;
uint8_t prot;
uint8_t type;
} type_protect;
struct {
void* dst;
void* src;
uint64_t len;
} move;
uintptr_t padding[3];
};
};
static_assert(sizeof(KernelMemoryPoolBatchEntry) == 32,
"KernelMemoryPoolBatchEntry struct size is incorrect");
struct KernelMemoryPoolBlockStats {
int32_t available_flushed_blocks;
int32_t available_cached_blocks;
int32_t allocated_flushed_blocks;
int32_t allocated_cached_blocks;
};
static_assert(sizeof(KernelMemoryPoolBlockStats) == 16,
"KernelMemoryPoolBlockStats struct size is incorrect");
void RegisterCallbacks(callback_func_t alloc_func, callback_func_t free_func);
void SetFlexibleMemorySize(uint64_t size);
bool TryWriteBacking(uint64_t vaddr, const void* data, uint64_t size);
bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size);
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept;
int KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags,
const char* name);
int KYTY_SYSV_ABI KernelMapFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags);
int KYTY_SYSV_ABI KernelSetVirtualRangeName(const void* addr, uint64_t len, const char* name);
int KYTY_SYSV_ABI KernelMunmap(uint64_t vaddr, size_t len);
size_t KYTY_SYSV_ABI KernelGetDirectMemorySize();
int KYTY_SYSV_ABI KernelAvailableDirectMemorySize(int64_t search_start, int64_t search_end,
size_t alignment, int64_t* phys_addr_out,
size_t* size_out);
int KYTY_SYSV_ABI KernelGetPageTableStats(int* cpu_total, int* cpu_available, int* gpu_total,
int* gpu_available);
int KYTY_SYSV_ABI KernelAllocateDirectMemory(int64_t search_start, int64_t search_end, size_t len,
size_t alignment, int memory_type,
int64_t* phys_addr_out);
int KYTY_SYSV_ABI KernelAllocateMainDirectMemory(size_t len, size_t alignment, int memory_type,
int64_t* phys_addr_out);
int KYTY_SYSV_ABI KernelCheckedReleaseDirectMemory(int64_t start, size_t len);
int KYTY_SYSV_ABI KernelReleaseDirectMemory(int64_t start, size_t len);
int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int flags,
int64_t direct_memory_start, size_t alignment);
int KYTY_SYSV_ABI KernelMapDirectMemory2(void** addr, size_t len, int type, int prot, int flags,
int64_t direct_memory_start, size_t alignment);
int KYTY_SYSV_ABI KernelMapNamedDirectMemory(void** addr, size_t len, int prot, int flags,
int64_t direct_memory_start, size_t alignment,
const char* name);
int KYTY_SYSV_ABI KernelSetPrtAperture(int index, void* addr, size_t len);
int KYTY_SYSV_ABI KernelGetPrtAperture(int index, void** addr, size_t* len);
int KYTY_SYSV_ABI KernelIsAddressSanitizerEnabled();
int KYTY_SYSV_ABI KernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot);
int KYTY_SYSV_ABI KernelDirectMemoryQuery(int64_t offset, int flags, void* info, size_t info_size);
int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info,
uint64_t info_size);
int KYTY_SYSV_ABI KernelIsStack(void* addr, void** start, void** end);
int KYTY_SYSV_ABI KernelReserveVirtualRange(void** addr, size_t len, int flags, size_t alignment);
bool KernelHandleReservedRangeAccessViolation(uint64_t vaddr);
int KYTY_SYSV_ABI KernelAvailableFlexibleMemorySize(size_t* size);
int KYTY_SYSV_ABI KernelConfiguredFlexibleMemorySize(uint64_t* size);
int KYTY_SYSV_ABI KernelMprotect(const void* addr, size_t len, int prot);
int KYTY_SYSV_ABI KernelMtypeprotect(const void* addr, size_t len, int type, int prot);
int KYTY_SYSV_ABI KernelBatchMap(KernelBatchMapEntry* entries, int num_entries,
int* num_entries_out);
int KYTY_SYSV_ABI KernelBatchMap2(KernelBatchMapEntry* entries, int num_entries,
int* num_entries_out, int flags);
int KYTY_SYSV_ABI KernelMemoryPoolExpand(int64_t search_start, int64_t search_end, size_t len,
size_t alignment, int64_t* phys_addr_out);
int KYTY_SYSV_ABI KernelMemoryPoolReserve(void* addr_in, size_t len, size_t alignment, int flags,
void** addr_out);
int KYTY_SYSV_ABI KernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags);
int KYTY_SYSV_ABI KernelMemoryPoolDecommit(void* addr, size_t len, int flags);
int KYTY_SYSV_ABI KernelMemoryPoolBatch(const KernelMemoryPoolBatchEntry* entries, int num_entries,
int* num_entries_out, int flags);
int KYTY_SYSV_ABI KernelMemoryPoolGetBlockStats(KernelMemoryPoolBlockStats* output,
size_t output_size);
void RegisterProgramMemory(uint64_t vaddr, uint64_t size, Common::VirtualMemory::Mode mode,
const char* name);
void UpdateProgramMemoryProtection(uint64_t vaddr, uint64_t size, Common::VirtualMemory::Mode mode);
void UnregisterProgramMemory(uint64_t vaddr, uint64_t size);
} // namespace Libs::LibKernel::Memory
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_MEMORY_H_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+283
View File
@@ -0,0 +1,283 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_
#include "common/abi.h"
#include "common/common.h"
#include "common/subsystems.h"
// IWYU pragma: no_include <pthread.h>
extern "C" {
struct sched_param;
}
namespace Loader {
struct Program;
} // namespace Loader
namespace Libs {
namespace LibKernel {
KYTY_SUBSYSTEM_DEFINE(Pthread);
struct PthreadAttrPrivate;
struct PthreadPrivate;
struct PthreadMutexPrivate;
struct PthreadMutexattrPrivate;
struct PthreadRwlockPrivate;
struct PthreadRwlockattrPrivate;
struct PthreadCondattrPrivate;
struct PthreadCondPrivate;
struct KernelTimespec {
int64_t tv_sec;
int64_t tv_nsec;
};
struct KernelTimeval {
int64_t tv_sec;
int64_t tv_usec;
};
struct KernelTimezone {
int32_t tz_minuteswest;
int32_t tz_dsttime;
};
struct KernelTimesec {
int64_t t;
uint32_t west_sec;
uint32_t dst_sec;
};
using PthreadAttr = PthreadAttrPrivate*;
using Pthread = PthreadPrivate*;
using KernelCpumask = uint64_t;
using PthreadMutex = PthreadMutexPrivate*;
using PthreadMutexattr = PthreadMutexattrPrivate*;
using KernelSchedParam = struct sched_param;
using PthreadRwlock = PthreadRwlockPrivate*;
using PthreadRwlockattr = PthreadRwlockattrPrivate*;
using KernelUseconds = unsigned int;
using PthreadCondattr = PthreadCondattrPrivate*;
using PthreadCond = PthreadCondPrivate*;
using KernelClockid = int32_t;
using PthreadKey = int;
using pthread_entry_func_t = KYTY_SYSV_ABI void* (*)(void*);
using thread_dtors_func_t = KYTY_SYSV_ABI void (*)();
using pthread_key_destructor_func_t = KYTY_SYSV_ABI void (*)(void*);
void PthreadInitSelfForMainThread();
void* PthreadCreateMainGuestStack();
void PthreadDeleteStaticObjects(Loader::Program* program);
int KYTY_SYSV_ABI PthreadMutexattrInit(PthreadMutexattr* attr);
int KYTY_SYSV_ABI PthreadMutexattrDestroy(PthreadMutexattr* attr);
int KYTY_SYSV_ABI PthreadMutexattrSettype(PthreadMutexattr* attr, int type);
int KYTY_SYSV_ABI PthreadMutexattrSetprotocol(PthreadMutexattr* attr, int protocol);
int KYTY_SYSV_ABI PthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr);
int KYTY_SYSV_ABI PthreadMutexDestroy(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexLock(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexTrylock(PthreadMutex* mutex);
int KYTY_SYSV_ABI PthreadMutexTimedlock(PthreadMutex* mutex, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadMutexUnlock(PthreadMutex* mutex);
Pthread KYTY_SYSV_ABI PthreadSelf();
Pthread PthreadSelfOrNull();
Pthread PthreadSwapSelfForSignal(Pthread thread);
int KYTY_SYSV_ABI PthreadCreate(Pthread* thread, const PthreadAttr* attr,
pthread_entry_func_t entry, void* arg, const char* name);
int KYTY_SYSV_ABI PthreadDetach(Pthread thread);
int KYTY_SYSV_ABI PthreadJoin(Pthread thread, void** value);
int KYTY_SYSV_ABI PthreadCancel(Pthread thread);
int KYTY_SYSV_ABI PthreadSetcancelstate(int state, int* old_state);
int KYTY_SYSV_ABI PthreadSetcanceltype(int type, int* old_type);
int KYTY_SYSV_ABI PthreadGetprio(Pthread thread, int* prio);
int KYTY_SYSV_ABI PthreadSetprio(Pthread thread, int prio);
void KYTY_SYSV_ABI PthreadTestcancel();
int KYTY_SYSV_ABI PthreadSetaffinity(Pthread thread, KernelCpumask mask);
void KYTY_SYSV_ABI PthreadExit(void* value);
int KYTY_SYSV_ABI PthreadEqual(Pthread thread1, Pthread thread2);
int KYTY_SYSV_ABI PthreadGetname(Pthread thread, char* name);
int KYTY_SYSV_ABI PthreadRename(Pthread thread, const char* name);
void KYTY_SYSV_ABI PthreadYield();
int KYTY_SYSV_ABI PthreadGetthreadid();
int KYTY_SYSV_ABI PthreadGetaffinity(Pthread thread, KernelCpumask* mask);
int PthreadGetUniqueId(Pthread thread);
uint64_t PthreadGetHostThreadId(Pthread thread);
void PthreadWakeForSignal(Pthread thread);
void PthreadQueuePendingSignal(Pthread thread, int signum);
bool PthreadHasPendingSignal(Pthread thread, int signum);
bool PthreadTakePendingSignal(Pthread thread, int signum);
bool PthreadGetGuestStack(Pthread thread, uint64_t* stack_addr, uint64_t* stack_size);
int PthreadGetPriorityForKernel(Pthread thread);
int PthreadGetCurrentPriorityForKernel();
int KYTY_SYSV_ABI KernelUsleep(KernelUseconds microseconds);
unsigned int KYTY_SYSV_ABI KernelSleep(unsigned int seconds);
int KYTY_SYSV_ABI KernelNanosleep(const KernelTimespec* rqtp, KernelTimespec* rmtp);
int KYTY_SYSV_ABI PthreadKeyCreate(PthreadKey* key, pthread_key_destructor_func_t destructor);
int KYTY_SYSV_ABI PthreadKeyDelete(PthreadKey key);
int KYTY_SYSV_ABI PthreadSetspecific(PthreadKey key, void* value);
void* KYTY_SYSV_ABI PthreadGetspecific(PthreadKey key);
void KYTY_SYSV_ABI KernelSetThreadDtors(thread_dtors_func_t dtors);
int KYTY_SYSV_ABI PthreadAttrInit(PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrDestroy(PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrGet(Pthread thread, PthreadAttr* attr);
int KYTY_SYSV_ABI PthreadAttrGetaffinity(const PthreadAttr* attr, KernelCpumask* mask);
int KYTY_SYSV_ABI PthreadAttrGetdetachstate(const PthreadAttr* attr, int* state);
int KYTY_SYSV_ABI PthreadAttrGetguardsize(const PthreadAttr* attr, size_t* guard_size);
int KYTY_SYSV_ABI PthreadAttrGetinheritsched(const PthreadAttr* attr, int* inherit_sched);
int KYTY_SYSV_ABI PthreadAttrGetschedparam(const PthreadAttr* attr, KernelSchedParam* param);
int KYTY_SYSV_ABI PthreadAttrGetschedpolicy(const PthreadAttr* attr, int* policy);
int KYTY_SYSV_ABI PthreadAttrGetsolosched(const PthreadAttr* attr, int* solosched);
int KYTY_SYSV_ABI PthreadAttrGetstack(const PthreadAttr* __restrict attr,
void** __restrict stack_addr, size_t* __restrict stack_size);
int KYTY_SYSV_ABI PthreadAttrGetstackaddr(const PthreadAttr* attr, void** stack_addr);
int KYTY_SYSV_ABI PthreadAttrGetstacksize(const PthreadAttr* attr, size_t* stack_size);
int KYTY_SYSV_ABI PthreadAttrSetaffinity(PthreadAttr* attr, KernelCpumask mask);
int KYTY_SYSV_ABI PthreadAttrSetdetachstate(PthreadAttr* attr, int state);
int KYTY_SYSV_ABI PthreadAttrSetguardsize(PthreadAttr* attr, size_t guard_size);
int KYTY_SYSV_ABI PthreadAttrSetinheritsched(PthreadAttr* attr, int inherit_sched);
int KYTY_SYSV_ABI PthreadAttrSetschedparam(PthreadAttr* attr, const KernelSchedParam* param);
int KYTY_SYSV_ABI PthreadAttrSetschedpolicy(PthreadAttr* attr, int policy);
int KYTY_SYSV_ABI PthreadAttrSetsolosched(PthreadAttr* attr, int solosched);
int KYTY_SYSV_ABI PthreadAttrSetstack(PthreadAttr* attr, void* addr, size_t size);
int KYTY_SYSV_ABI PthreadAttrSetstackaddr(PthreadAttr* attr, void* addr);
int KYTY_SYSV_ABI PthreadAttrSetstacksize(PthreadAttr* attr, size_t stack_size);
int KYTY_SYSV_ABI PthreadRwlockDestroy(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockInit(PthreadRwlock* rwlock, const PthreadRwlockattr* attr);
int KYTY_SYSV_ABI PthreadRwlockRdlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockTimedrdlock(PthreadRwlock* rwlock, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadRwlockTimedwrlock(PthreadRwlock* rwlock, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadRwlockTryrdlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockTrywrlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockUnlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockWrlock(PthreadRwlock* rwlock);
int KYTY_SYSV_ABI PthreadRwlockattrDestroy(PthreadRwlockattr* attr);
int KYTY_SYSV_ABI PthreadRwlockattrInit(PthreadRwlockattr* attr);
int KYTY_SYSV_ABI PthreadRwlockattrGettype(PthreadRwlockattr* attr, int* type);
int KYTY_SYSV_ABI PthreadRwlockattrSettype(PthreadRwlockattr* attr, int type);
int KYTY_SYSV_ABI PthreadCondattrDestroy(PthreadCondattr* attr);
int KYTY_SYSV_ABI PthreadCondattrInit(PthreadCondattr* attr);
int KYTY_SYSV_ABI PthreadCondattrSetclock(PthreadCondattr* attr, KernelClockid clock_id);
int KYTY_SYSV_ABI PthreadCondBroadcast(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondDestroy(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondInit(PthreadCond* cond, const PthreadCondattr* attr);
int KYTY_SYSV_ABI PthreadCondSignal(PthreadCond* cond);
int KYTY_SYSV_ABI PthreadCondSignalto(PthreadCond* cond, Pthread thread);
int KYTY_SYSV_ABI PthreadCondTimedwait(PthreadCond* cond, PthreadMutex* mutex, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadCondTimedwaitAbs(PthreadCond* cond, PthreadMutex* mutex,
const KernelTimespec* abstime);
int KYTY_SYSV_ABI PthreadCondWait(PthreadCond* cond, PthreadMutex* mutex);
int KYTY_SYSV_ABI KernelClockGetres(KernelClockid clock_id, KernelTimespec* tp);
int KYTY_SYSV_ABI KernelClockGettime(KernelClockid clock_id, KernelTimespec* tp);
int KYTY_SYSV_ABI KernelGettimeofday(KernelTimeval* tp);
int KYTY_SYSV_ABI KernelGettimezone(KernelTimezone* tz);
int KYTY_SYSV_ABI KernelConvertLocaltimeToUtc(int64_t local_time, int64_t reserved,
int64_t* utc_time, KernelTimezone* timezone,
int32_t* dst_seconds);
int KYTY_SYSV_ABI KernelConvertUtcToLocaltime(int64_t utc_time, int64_t* local_time,
KernelTimesec* st, uint64_t* dst_sec);
uint64_t KYTY_SYSV_ABI KernelGetTscFrequency();
uint64_t KYTY_SYSV_ABI KernelReadTsc();
uint64_t KYTY_SYSV_ABI KernelGetProcessTime();
uint64_t KYTY_SYSV_ABI KernelGetProcessTimeCounter();
uint64_t KYTY_SYSV_ABI KernelGetProcessTimeCounterFrequency();
} // namespace LibKernel
namespace Posix {
int KYTY_SYSV_ABI pthread_create(LibKernel::Pthread* thread, const LibKernel::PthreadAttr* attr,
LibKernel::pthread_entry_func_t entry, void* arg);
int KYTY_SYSV_ABI pthread_create_name_np(LibKernel::Pthread* thread,
const LibKernel::PthreadAttr* attr,
LibKernel::pthread_entry_func_t entry, void* arg,
const char* name);
int KYTY_SYSV_ABI pthread_detach(LibKernel::Pthread thread);
void KYTY_SYSV_ABI pthread_exit(void* value);
LibKernel::Pthread KYTY_SYSV_ABI pthread_self();
int KYTY_SYSV_ABI pthread_rename_np(LibKernel::Pthread thread, const char* name);
int KYTY_SYSV_ABI pthread_setcancelstate(int state, int* old_state);
int KYTY_SYSV_ABI pthread_setprio(LibKernel::Pthread thread, int prio);
int KYTY_SYSV_ABI pthread_getschedparam(LibKernel::Pthread thread, int* policy,
LibKernel::KernelSchedParam* param);
int KYTY_SYSV_ABI pthread_setschedparam(LibKernel::Pthread thread, int policy,
const LibKernel::KernelSchedParam* param);
void KYTY_SYSV_ABI pthread_yield();
int KYTY_SYSV_ABI sched_get_priority_max(int policy);
int KYTY_SYSV_ABI sched_get_priority_min(int policy);
int KYTY_SYSV_ABI pthread_join(LibKernel::Pthread thread, void** value);
int KYTY_SYSV_ABI pthread_attr_init(LibKernel::PthreadAttr* attr);
int KYTY_SYSV_ABI pthread_attr_destroy(LibKernel::PthreadAttr* attr);
int KYTY_SYSV_ABI pthread_attr_get_np(LibKernel::Pthread thread, LibKernel::PthreadAttr* attr);
int KYTY_SYSV_ABI pthread_attr_getdetachstate(const LibKernel::PthreadAttr* attr, int* state);
int KYTY_SYSV_ABI pthread_attr_getguardsize(const LibKernel::PthreadAttr* attr, size_t* guard_size);
int KYTY_SYSV_ABI pthread_attr_getinheritsched(const LibKernel::PthreadAttr* attr,
int* inherit_sched);
int KYTY_SYSV_ABI pthread_attr_getschedparam(const LibKernel::PthreadAttr* attr,
LibKernel::KernelSchedParam* param);
int KYTY_SYSV_ABI pthread_attr_getschedpolicy(const LibKernel::PthreadAttr* attr, int* policy);
int KYTY_SYSV_ABI pthread_attr_getstack(const LibKernel::PthreadAttr* __restrict attr,
void** __restrict stack_addr,
size_t* __restrict stack_size);
int KYTY_SYSV_ABI pthread_attr_getstacksize(const LibKernel::PthreadAttr* attr, size_t* stack_size);
int KYTY_SYSV_ABI pthread_attr_setdetachstate(LibKernel::PthreadAttr* attr, int state);
int KYTY_SYSV_ABI pthread_attr_setguardsize(LibKernel::PthreadAttr* attr, size_t guard_size);
int KYTY_SYSV_ABI pthread_attr_setinheritsched(LibKernel::PthreadAttr* attr, int inherit_sched);
int KYTY_SYSV_ABI pthread_attr_setschedparam(LibKernel::PthreadAttr* attr,
const LibKernel::KernelSchedParam* param);
int KYTY_SYSV_ABI pthread_attr_setschedpolicy(LibKernel::PthreadAttr* attr, int policy);
int KYTY_SYSV_ABI pthread_attr_setstacksize(LibKernel::PthreadAttr* attr, size_t stack_size);
int KYTY_SYSV_ABI pthread_cond_broadcast(LibKernel::PthreadCond* cond);
int KYTY_SYSV_ABI pthread_cond_signal(LibKernel::PthreadCond* cond);
int KYTY_SYSV_ABI pthread_cond_init(LibKernel::PthreadCond* cond,
const LibKernel::PthreadCondattr* attr);
int KYTY_SYSV_ABI pthread_condattr_init(LibKernel::PthreadCondattr* attr);
int KYTY_SYSV_ABI pthread_condattr_destroy(LibKernel::PthreadCondattr* attr);
int KYTY_SYSV_ABI pthread_condattr_setclock(LibKernel::PthreadCondattr* attr,
LibKernel::KernelClockid clock_id);
int KYTY_SYSV_ABI pthread_cond_wait(LibKernel::PthreadCond* cond, LibKernel::PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_cond_timedwait(LibKernel::PthreadCond* cond,
LibKernel::PthreadMutex* mutex,
const LibKernel::KernelTimespec* abstime);
int KYTY_SYSV_ABI pthread_once(void* once_control, void(KYTY_SYSV_ABI* init_routine)());
int KYTY_SYSV_ABI pthread_mutex_lock(LibKernel::PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_mutex_trylock(LibKernel::PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_mutex_timedlock(LibKernel::PthreadMutex* mutex,
const LibKernel::KernelTimespec* abstime);
int KYTY_SYSV_ABI pthread_mutex_unlock(LibKernel::PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_rwlock_rdlock(LibKernel::PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_rwlock_unlock(LibKernel::PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_rwlock_wrlock(LibKernel::PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_rwlock_destroy(LibKernel::PthreadRwlock* rwlock);
int KYTY_SYSV_ABI pthread_key_create(LibKernel::PthreadKey* key,
LibKernel::pthread_key_destructor_func_t destructor);
int KYTY_SYSV_ABI pthread_key_delete(LibKernel::PthreadKey key);
int KYTY_SYSV_ABI pthread_setspecific(LibKernel::PthreadKey key, void* value);
void* KYTY_SYSV_ABI pthread_getspecific(LibKernel::PthreadKey key);
int KYTY_SYSV_ABI pthread_mutex_destroy(LibKernel::PthreadMutex* mutex);
int KYTY_SYSV_ABI pthread_mutex_init(LibKernel::PthreadMutex* mutex,
const LibKernel::PthreadMutexattr* attr);
int KYTY_SYSV_ABI pthread_mutexattr_init(LibKernel::PthreadMutexattr* attr);
int KYTY_SYSV_ABI pthread_mutexattr_settype(LibKernel::PthreadMutexattr* attr, int type);
int KYTY_SYSV_ABI pthread_mutexattr_setprotocol(LibKernel::PthreadMutexattr* attr, int protocol);
int KYTY_SYSV_ABI pthread_mutexattr_destroy(LibKernel::PthreadMutexattr* attr);
int KYTY_SYSV_ABI pthread_getstack(const LibKernel::PthreadAttr* __restrict attr,
void** __restrict stack_addr, size_t* __restrict stack_size);
int64_t KYTY_SYSV_ABI lseek(int d, int64_t offset, int whence);
} // namespace Posix
} // namespace Libs
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_PTHREAD_H_ */
+745
View File
@@ -0,0 +1,745 @@
#include "kernel/semaphore.h"
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/stringUtils.h"
#include "common/threads.h"
#include "common/timer.h"
#include "libs/errno.h"
#include "libs/libs.h"
#include <algorithm>
#include <limits>
#include <unordered_map>
#include <vector>
namespace Libs::LibKernel {
void KernelDispatchPendingSignalForCurrentThread();
} // namespace Libs::LibKernel
namespace Libs::LibKernel::Semaphore {
LIB_NAME("libkernel", "libkernel");
constexpr uint32_t SIGNAL_APC_POLL_MICROS = 10000;
class KernelSemaPrivate {
public:
enum class Result { Ok, TimedOut, Canceled, Deleted, InvalCount };
KernelSemaPrivate(const std::string& name, bool fifo, int init_count, int max_count)
: m_name(name), m_fifo_order(fifo), m_count(init_count), m_init_count(init_count),
m_max_count(max_count) {};
virtual ~KernelSemaPrivate();
KYTY_CLASS_NO_COPY(KernelSemaPrivate);
Result Cancel(int set_count, int* num_waiting_threads);
Result Signal(int signal_count);
Result Wait(int need_count, uint32_t* ptr_micros);
Result Poll(int need_count) {
uint32_t micros = 0;
return Wait(need_count, &micros);
}
[[nodiscard]] const std::string& GetName() const { return m_name; }
private:
enum class Status { Set, Deleted };
struct WaitingThread {
int id = 0;
int priority = 700;
int need_count = 0;
Result result = Result::TimedOut;
bool ready = false;
};
void AddWaiter(WaitingThread* waiter);
void RemoveWaiter(WaitingThread* waiter);
void WakeWaiters();
Common::Mutex m_mutex;
Common::CondVar m_cond_var;
std::string m_name;
Status m_status = Status::Set;
std::vector<WaitingThread*> m_waiting_threads;
bool m_fifo_order;
int m_count;
int m_init_count;
int m_max_count;
};
KernelSemaPrivate::~KernelSemaPrivate() {
Common::LockGuard lock(m_mutex);
while (m_status != Status::Set) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
m_status = Status::Deleted;
for (auto* waiter: m_waiting_threads) {
if (!waiter->ready) {
waiter->result = Result::Deleted;
waiter->ready = true;
}
}
m_cond_var.SignalAll();
while (!m_waiting_threads.empty()) {
m_mutex.Unlock();
Common::Thread::SleepMicro(10);
m_mutex.Lock();
}
}
KernelSemaPrivate::Result KernelSemaPrivate::Cancel(int set_count, int* num_waiting_threads) {
Common::LockGuard lock(m_mutex);
if (set_count > m_max_count) {
return Result::InvalCount;
}
if (m_status == Status::Deleted) {
return Result::Deleted;
}
if (num_waiting_threads != nullptr) {
*num_waiting_threads = static_cast<int>(
std::count_if(m_waiting_threads.begin(), m_waiting_threads.end(),
[](const WaitingThread* waiter) { return !waiter->ready; }));
}
m_count = (set_count < 0 ? m_init_count : set_count);
for (auto* waiter: m_waiting_threads) {
if (!waiter->ready) {
waiter->result = Result::Canceled;
waiter->ready = true;
}
}
m_cond_var.SignalAll();
return Result::Ok;
}
KernelSemaPrivate::Result KernelSemaPrivate::Signal(int signal_count) {
Common::LockGuard lock(m_mutex);
if (m_status == Status::Deleted) {
return Result::Deleted;
}
if (m_count + signal_count > m_max_count) {
return Result::InvalCount;
}
m_count += signal_count;
WakeWaiters();
m_cond_var.SignalAll();
return Result::Ok;
}
void KernelSemaPrivate::AddWaiter(WaitingThread* waiter) {
if (m_fifo_order) {
m_waiting_threads.push_back(waiter);
return;
}
auto it = m_waiting_threads.begin();
while (it != m_waiting_threads.end() && (*it)->priority <= waiter->priority) {
++it;
}
m_waiting_threads.insert(it, waiter);
}
void KernelSemaPrivate::RemoveWaiter(WaitingThread* waiter) {
auto it = std::find(m_waiting_threads.begin(), m_waiting_threads.end(), waiter);
if (it != m_waiting_threads.end()) {
m_waiting_threads.erase(it);
}
}
void KernelSemaPrivate::WakeWaiters() {
for (auto* waiter: m_waiting_threads) {
if (!waiter->ready && waiter->need_count <= m_count) {
m_count -= waiter->need_count;
waiter->result = Result::Ok;
waiter->ready = true;
}
}
}
KernelSemaPrivate::Result KernelSemaPrivate::Wait(int need_count, uint32_t* ptr_micros) {
Common::LockGuard lock(m_mutex);
if (need_count < 1 || need_count > m_max_count) {
return Result::InvalCount;
}
if (m_status == Status::Deleted) {
return Result::Deleted;
}
uint32_t micros = 0;
bool infinitely = true;
if (ptr_micros != nullptr) {
micros = *ptr_micros;
infinitely = false;
}
uint32_t elapsed = 0;
Common::Timer t;
t.Start();
int id = Common::Thread::GetThreadIdUnique();
if (m_count >= need_count) {
m_count -= need_count;
if (ptr_micros != nullptr) {
*ptr_micros = micros;
}
return Result::Ok;
}
if (!infinitely && micros == 0) {
return Result::TimedOut;
}
WaitingThread waiter {};
waiter.id = id;
waiter.priority = (m_fifo_order ? 0 : Libs::LibKernel::PthreadGetCurrentPriorityForKernel());
waiter.need_count = need_count;
AddWaiter(&waiter);
while (!waiter.ready) {
if ((elapsed >= micros && !infinitely)) {
RemoveWaiter(&waiter);
*ptr_micros = 0;
return Result::TimedOut;
}
if (infinitely) {
m_cond_var.WaitFor(&m_mutex, SIGNAL_APC_POLL_MICROS);
} else {
m_cond_var.WaitFor(&m_mutex, micros - elapsed);
}
m_mutex.Unlock();
LibKernel::KernelDispatchPendingSignalForCurrentThread();
m_mutex.Lock();
elapsed = static_cast<uint32_t>(t.GetTimeS() * 1000000.0);
}
RemoveWaiter(&waiter);
if (ptr_micros != nullptr) {
*ptr_micros = (elapsed >= micros ? 0 : micros - elapsed);
}
return waiter.result;
}
int KYTY_SYSV_ABI KernelCreateSema(KernelSema* sem, const char* name, uint32_t attr, int init,
int max, void* opt) {
PRINT_NAME();
EXIT_NOT_IMPLEMENTED(sem == nullptr);
if (name == nullptr || attr > 2 || init < 0 || max <= 0 || init > max) {
return KERNEL_ERROR_EINVAL;
}
bool fifo = false;
switch (attr) {
case 0x01: fifo = true; break;
case 0x02:
default: fifo = false; break;
}
*sem = new KernelSemaPrivate(std::string(name), fifo, init, max);
LOGF("\t Semaphore create: %s, ptr=0x%016" PRIx64 ", init=%d, max=%d\n", name,
reinterpret_cast<uint64_t>(*sem), init, max);
return OK;
}
int KYTY_SYSV_ABI KernelDeleteSema(KernelSema sem) {
PRINT_NAME();
if (sem == nullptr) {
return KERNEL_ERROR_ESRCH;
}
delete sem;
return OK;
}
int KYTY_SYSV_ABI KernelWaitSema(KernelSema sem, int need, KernelUseconds* time) {
if (sem == nullptr) {
return KERNEL_ERROR_ESRCH;
}
auto result = sem->Wait(need, time);
int ret = OK;
switch (result) {
case KernelSemaPrivate::Result::Ok: ret = OK; break;
case KernelSemaPrivate::Result::InvalCount: ret = KERNEL_ERROR_EINVAL; break;
case KernelSemaPrivate::Result::TimedOut: ret = KERNEL_ERROR_ETIMEDOUT; break;
case KernelSemaPrivate::Result::Canceled: ret = KERNEL_ERROR_ECANCELED; break;
case KernelSemaPrivate::Result::Deleted: ret = KERNEL_ERROR_EACCES; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelPollSema(KernelSema sem, int need) {
PRINT_NAME();
if (sem == nullptr) {
return KERNEL_ERROR_ESRCH;
}
LOGF("\t Semaphore poll: %s, %d\n", sem->GetName().c_str(), need);
auto result = sem->Poll(need);
int ret = OK;
switch (result) {
case KernelSemaPrivate::Result::Ok: ret = OK; break;
case KernelSemaPrivate::Result::InvalCount: ret = KERNEL_ERROR_EINVAL; break;
case KernelSemaPrivate::Result::TimedOut:
case KernelSemaPrivate::Result::Canceled:
case KernelSemaPrivate::Result::Deleted: ret = KERNEL_ERROR_EBUSY; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelSignalSema(KernelSema sem, int count) {
if (sem == nullptr) {
return KERNEL_ERROR_ESRCH;
}
auto result = sem->Signal(count);
int ret = OK;
switch (result) {
case KernelSemaPrivate::Result::Ok: ret = OK; break;
case KernelSemaPrivate::Result::InvalCount:
case KernelSemaPrivate::Result::TimedOut:
case KernelSemaPrivate::Result::Canceled:
case KernelSemaPrivate::Result::Deleted: ret = KERNEL_ERROR_EINVAL; break;
}
return ret;
}
int KYTY_SYSV_ABI KernelCancelSema(KernelSema sem, int count, int* threads) {
PRINT_NAME();
if (sem == nullptr) {
return KERNEL_ERROR_ESRCH;
}
auto result = sem->Cancel(count, threads);
int ret = OK;
switch (result) {
case KernelSemaPrivate::Result::Ok: ret = OK; break;
case KernelSemaPrivate::Result::InvalCount:
case KernelSemaPrivate::Result::TimedOut:
case KernelSemaPrivate::Result::Canceled:
case KernelSemaPrivate::Result::Deleted: ret = KERNEL_ERROR_EINVAL; break;
}
return ret;
}
} // namespace Libs::LibKernel::Semaphore
namespace Libs::Posix {
LIB_NAME("Posix", "libkernel");
namespace {
constexpr uint16_t POSIX_SEM_MAGIC = 0x09fa;
constexpr int POSIX_SEM_VALUE_MAX = 0x7fffffff;
constexpr uint32_t SIGNAL_APC_POLL_MICROS = 10000;
struct PosixSemGuest {
uint16_t magic;
uint16_t nameid;
volatile uint32_t has_waiters;
volatile uint32_t count;
uint32_t flags;
};
static_assert(sizeof(PosixSemGuest) == 16);
class PosixSemPrivate {
public:
PosixSemPrivate(PosixSemGuest* guest, unsigned int value, uint32_t flags)
: m_guest(guest), m_count(static_cast<int>(value)) {
SyncGuest(flags);
}
int Wait(uint32_t* micros) {
Common::LockGuard lock(m_mutex);
uint32_t elapsed = 0;
const bool timed_wait = (micros != nullptr);
Common::Timer timer;
timer.Start();
while (m_count <= 0) {
if (timed_wait && elapsed >= *micros) {
SyncGuest();
return POSIX_ETIMEDOUT;
}
m_waiters++;
SyncGuest();
if (timed_wait) {
m_cond_var.WaitFor(&m_mutex, *micros - elapsed);
} else {
m_cond_var.WaitFor(&m_mutex, SIGNAL_APC_POLL_MICROS);
}
m_mutex.Unlock();
LibKernel::KernelDispatchPendingSignalForCurrentThread();
m_mutex.Lock();
m_waiters--;
elapsed = static_cast<uint32_t>(timer.GetTimeS() * 1000000.0);
}
m_count--;
SyncGuest();
return OK;
}
int TryWait() {
Common::LockGuard lock(m_mutex);
if (m_count <= 0) {
SyncGuest();
return POSIX_EAGAIN;
}
m_count--;
SyncGuest();
return OK;
}
int Post() {
Common::LockGuard lock(m_mutex);
if (m_count == POSIX_SEM_VALUE_MAX) {
return POSIX_EOVERFLOW;
}
m_count++;
SyncGuest();
m_cond_var.Signal();
return OK;
}
int GetValue() {
Common::LockGuard lock(m_mutex);
return m_count;
}
private:
void SyncGuest(uint32_t flags = std::numeric_limits<uint32_t>::max()) {
if (m_guest != nullptr) {
m_guest->magic = POSIX_SEM_MAGIC;
m_guest->nameid = 0;
m_guest->has_waiters = (m_waiters > 0 ? 1u : 0u);
m_guest->count = static_cast<uint32_t>(m_count);
if (flags != std::numeric_limits<uint32_t>::max()) {
m_guest->flags = flags;
}
}
}
Common::Mutex m_mutex;
Common::CondVar m_cond_var;
PosixSemGuest* m_guest = nullptr;
int m_count = 0;
uint32_t m_waiters = 0;
};
Common::Mutex g_posix_sem_mutex;
std::unordered_map<PosixSemGuest*, PosixSemPrivate*> g_posix_sems;
static int PosixToKernel(int posix_errno) {
return (posix_errno >= 0 && posix_errno <= 102 ? posix_errno - 2147352576
: LibKernel::KERNEL_ERROR_EINVAL);
}
static PosixSemPrivate* GetSem(void* sem) {
if (sem == nullptr) {
return nullptr;
}
Common::LockGuard lock(g_posix_sem_mutex);
const auto it = g_posix_sems.find(static_cast<PosixSemGuest*>(sem));
return (it != g_posix_sems.end() ? it->second : nullptr);
}
static int SetErrnoReturn(int posix_errno) {
*GetErrorAddr() = posix_errno;
return -1;
}
static int SemInitImpl(void* sem, int pshared, unsigned int value, const char* name) {
if (sem == nullptr || value > POSIX_SEM_VALUE_MAX) {
return POSIX_EINVAL;
}
auto* guest = static_cast<PosixSemGuest*>(sem);
auto* obj = new PosixSemPrivate(guest, value, static_cast<uint32_t>(pshared));
{
Common::LockGuard lock(g_posix_sem_mutex);
if (auto it = g_posix_sems.find(guest); it != g_posix_sems.end()) {
delete it->second;
it->second = obj;
} else {
g_posix_sems.insert({guest, obj});
}
}
static std::atomic<uint32_t> log_count {0};
const auto count = log_count.fetch_add(1);
if (count < 32) {
LOGF("\t POSIX semaphore init: %s, value = %u, pshared = %d\n",
(name != nullptr ? name : "sem"), value, pshared);
}
return OK;
}
static int SemDestroyImpl(void* sem) {
if (sem == nullptr) {
return POSIX_EINVAL;
}
auto* guest = static_cast<PosixSemGuest*>(sem);
PosixSemPrivate* obj = nullptr;
{
Common::LockGuard lock(g_posix_sem_mutex);
const auto it = g_posix_sems.find(guest);
if (it == g_posix_sems.end()) {
return POSIX_EINVAL;
}
obj = it->second;
g_posix_sems.erase(it);
}
delete obj;
guest->magic = 0;
guest->has_waiters = 0;
guest->count = 0;
guest->flags = 0;
return OK;
}
static int SemTimedwaitImpl(void* sem, uint32_t* micros) {
auto* obj = GetSem(sem);
if (obj == nullptr) {
return POSIX_EINVAL;
}
return obj->Wait(micros);
}
static bool AbsTimespecToMicros(const LibKernel::KernelTimespec* abstime, uint32_t* micros) {
if (abstime == nullptr || micros == nullptr || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000) {
return false;
}
LibKernel::KernelTimespec now {};
if (LibKernel::KernelClockGettime(0, &now) != OK) {
return false;
}
const int64_t sec_delta = abstime->tv_sec - now.tv_sec;
const int64_t nsec_delta = abstime->tv_nsec - now.tv_nsec;
const int64_t usec_delta = sec_delta * 1000000 + nsec_delta / 1000;
if (usec_delta <= 0) {
*micros = 0;
} else if (usec_delta > std::numeric_limits<uint32_t>::max()) {
*micros = std::numeric_limits<uint32_t>::max();
} else {
*micros = static_cast<uint32_t>(usec_delta);
}
return true;
}
} // namespace
int KYTY_SYSV_ABI sem_init(void* sem, int pshared, unsigned int value) {
PRINT_NAME();
const int result = SemInitImpl(sem, pshared, value, nullptr);
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_destroy(void* sem) {
PRINT_NAME();
const int result = SemDestroyImpl(sem);
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_wait(void* sem) {
const int result = SemTimedwaitImpl(sem, nullptr);
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_trywait(void* sem) {
auto* obj = GetSem(sem);
if (obj == nullptr) {
return SetErrnoReturn(POSIX_EINVAL);
}
const int result = obj->TryWait();
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_reltimedwait_np(void* sem, uint32_t usec) {
const int result = SemTimedwaitImpl(sem, &usec);
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_timedwait(void* sem, const LibKernel::KernelTimespec* abstime) {
uint32_t micros = 0;
if (!AbsTimespecToMicros(abstime, &micros)) {
return SetErrnoReturn(POSIX_EINVAL);
}
const int result = SemTimedwaitImpl(sem, &micros);
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_post(void* sem) {
auto* obj = GetSem(sem);
if (obj == nullptr) {
return SetErrnoReturn(POSIX_EINVAL);
}
const int result = obj->Post();
return (result == OK ? 0 : SetErrnoReturn(result));
}
int KYTY_SYSV_ABI sem_getvalue(void* sem, int* value) {
auto* obj = GetSem(sem);
if (obj == nullptr || value == nullptr) {
return SetErrnoReturn(POSIX_EINVAL);
}
*value = obj->GetValue();
return 0;
}
} // namespace Libs::Posix
namespace Libs::LibKernel::Semaphore {
int KYTY_SYSV_ABI PthreadSemInit(void* sem, int flag, unsigned int value, const char* name) {
PRINT_NAME();
if (flag != 0) {
return KERNEL_ERROR_EINVAL;
}
const int result = Posix::SemInitImpl(sem, 0, value, name);
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemDestroy(void* sem) {
PRINT_NAME();
const int result = Posix::SemDestroyImpl(sem);
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemWait(void* sem) {
const int result = Posix::SemTimedwaitImpl(sem, nullptr);
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemTrywait(void* sem) {
auto* obj = Posix::GetSem(sem);
if (obj == nullptr) {
return KERNEL_ERROR_EINVAL;
}
const int result = obj->TryWait();
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemTimedwait(void* sem, KernelUseconds usec) {
uint32_t micros = usec;
const int result = Posix::SemTimedwaitImpl(sem, &micros);
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemPost(void* sem) {
auto* obj = Posix::GetSem(sem);
if (obj == nullptr) {
return KERNEL_ERROR_EINVAL;
}
const int result = obj->Post();
return (result == OK ? OK : Posix::PosixToKernel(result));
}
int KYTY_SYSV_ABI PthreadSemGetvalue(void* sem, int* value) {
auto* obj = Posix::GetSem(sem);
if (obj == nullptr || value == nullptr) {
return KERNEL_ERROR_EINVAL;
}
*value = obj->GetValue();
return OK;
}
} // namespace Libs::LibKernel::Semaphore
+44
View File
@@ -0,0 +1,44 @@
#ifndef EMULATOR_INCLUDE_EMULATOR_KERNEL_SEMAPHORE_H_
#define EMULATOR_INCLUDE_EMULATOR_KERNEL_SEMAPHORE_H_
#include "common/abi.h"
#include "common/common.h"
#include "kernel/pthread.h"
namespace Libs::LibKernel::Semaphore {
class KernelSemaPrivate;
using KernelSema = KernelSemaPrivate*;
int KYTY_SYSV_ABI KernelCreateSema(KernelSema* sem, const char* name, uint32_t attr, int init,
int max, void* opt);
int KYTY_SYSV_ABI KernelDeleteSema(KernelSema sem);
int KYTY_SYSV_ABI KernelWaitSema(KernelSema sem, int need, KernelUseconds* time);
int KYTY_SYSV_ABI KernelPollSema(KernelSema sem, int need);
int KYTY_SYSV_ABI KernelSignalSema(KernelSema sem, int count);
int KYTY_SYSV_ABI KernelCancelSema(KernelSema sem, int count, int* threads);
int KYTY_SYSV_ABI PthreadSemInit(void* sem, int flag, unsigned int value, const char* name);
int KYTY_SYSV_ABI PthreadSemDestroy(void* sem);
int KYTY_SYSV_ABI PthreadSemWait(void* sem);
int KYTY_SYSV_ABI PthreadSemTrywait(void* sem);
int KYTY_SYSV_ABI PthreadSemTimedwait(void* sem, KernelUseconds usec);
int KYTY_SYSV_ABI PthreadSemPost(void* sem);
int KYTY_SYSV_ABI PthreadSemGetvalue(void* sem, int* value);
} // namespace Libs::LibKernel::Semaphore
namespace Libs::Posix {
int KYTY_SYSV_ABI sem_init(void* sem, int pshared, unsigned int value);
int KYTY_SYSV_ABI sem_destroy(void* sem);
int KYTY_SYSV_ABI sem_wait(void* sem);
int KYTY_SYSV_ABI sem_trywait(void* sem);
int KYTY_SYSV_ABI sem_reltimedwait_np(void* sem, uint32_t usec);
int KYTY_SYSV_ABI sem_timedwait(void* sem, const LibKernel::KernelTimespec* abstime);
int KYTY_SYSV_ABI sem_post(void* sem);
int KYTY_SYSV_ABI sem_getvalue(void* sem, int* value);
} // namespace Libs::Posix
#endif /* EMULATOR_INCLUDE_EMULATOR_KERNEL_SEMAPHORE_H_ */