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
+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