2023-10-30 22:09:15 +01:00
|
|
|
#include "KernelAllocator.hpp"
|
2023-07-03 13:10:16 +02:00
|
|
|
#include "sys/sysproto.hpp"
|
|
|
|
|
|
2023-07-12 03:20:28 +02:00
|
|
|
#include "thread/Process.hpp"
|
|
|
|
|
#include "utils/Logs.hpp"
|
2023-10-30 22:09:15 +01:00
|
|
|
#include "utils/SharedMutex.hpp"
|
2023-10-31 23:58:03 +01:00
|
|
|
#include <chrono>
|
2023-10-30 22:09:15 +01:00
|
|
|
#include <list>
|
|
|
|
|
#include <span>
|
2023-10-31 23:58:03 +01:00
|
|
|
#include <thread>
|
2023-07-12 03:20:28 +02:00
|
|
|
|
2023-10-30 22:09:15 +01:00
|
|
|
namespace orbis {
|
|
|
|
|
struct KEvent {
|
|
|
|
|
uintptr_t ident;
|
|
|
|
|
sshort filter;
|
|
|
|
|
ushort flags;
|
|
|
|
|
uint fflags;
|
|
|
|
|
intptr_t data;
|
|
|
|
|
ptr<void> udata;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct KNote {
|
|
|
|
|
KEvent event;
|
|
|
|
|
bool enabled;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct KQueue : orbis::File {
|
|
|
|
|
std::list<KNote, kallocator<KNote>> notes;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static constexpr auto kEvFiltRead = -1;
|
|
|
|
|
static constexpr auto kEvFiltWrite = -2;
|
|
|
|
|
static constexpr auto kEvFiltAio = -3;
|
|
|
|
|
static constexpr auto kEvFiltVnode = -4;
|
|
|
|
|
static constexpr auto kEvFiltProc = -5;
|
|
|
|
|
static constexpr auto kEvFiltSignal = -6;
|
|
|
|
|
static constexpr auto kEvFiltTimer = -7;
|
|
|
|
|
static constexpr auto kEvFiltFs = -9;
|
|
|
|
|
static constexpr auto kEvFiltLio = -10;
|
|
|
|
|
static constexpr auto kEvFiltUser = -11;
|
|
|
|
|
static constexpr auto kEvFiltPolling = -12;
|
|
|
|
|
static constexpr auto kEvFiltDisplay = -13;
|
|
|
|
|
static constexpr auto kEvFiltGraphicsCore = -14;
|
|
|
|
|
static constexpr auto kEvFiltHrTimer = -15;
|
|
|
|
|
static constexpr auto kEvFiltUvdTrap = -16;
|
|
|
|
|
static constexpr auto kEvFiltVceTrap = -17;
|
|
|
|
|
static constexpr auto kEvFiltSdmaTrap = -18;
|
|
|
|
|
static constexpr auto kEvFiltRegEv = -19;
|
|
|
|
|
static constexpr auto kEvFiltGpuException = -20;
|
|
|
|
|
static constexpr auto kEvFiltGpuSystemException = -21;
|
|
|
|
|
static constexpr auto kEvFiltGpuDbgGcEv = -22;
|
|
|
|
|
static constexpr auto kEvFiltSysCount = 22;
|
|
|
|
|
|
|
|
|
|
// actions
|
|
|
|
|
static constexpr auto kEvAdd = 0x0001;
|
|
|
|
|
static constexpr auto kEvDelete = 0x0002;
|
|
|
|
|
static constexpr auto kEvEnable = 0x0004;
|
|
|
|
|
static constexpr auto kEvDisable = 0x0008;
|
|
|
|
|
|
|
|
|
|
// flags
|
|
|
|
|
static constexpr auto kEvOneshot = 0x0010;
|
|
|
|
|
static constexpr auto kEvClear = 0x0020;
|
|
|
|
|
static constexpr auto kEvReceipt = 0x0040;
|
|
|
|
|
static constexpr auto kEvDispatch = 0x0080;
|
|
|
|
|
static constexpr auto kEvSysFlags = 0xf000;
|
|
|
|
|
static constexpr auto kEvFlag1 = 0x2000;
|
|
|
|
|
|
|
|
|
|
static constexpr auto kEvEof = 0x8000;
|
|
|
|
|
static constexpr auto kEvError = 0x4000;
|
2023-11-03 20:12:59 +01:00
|
|
|
|
|
|
|
|
// kEvFiltUser
|
|
|
|
|
static constexpr auto kNoteFFNop = 0x00000000;
|
|
|
|
|
static constexpr auto kNoteFFAnd = 0x40000000;
|
|
|
|
|
static constexpr auto kNoteFFOr = 0x80000000;
|
|
|
|
|
static constexpr auto kNoteFFCopy = 0xc0000000;
|
|
|
|
|
static constexpr auto kNoteFFCtrlMask = 0xc0000000;
|
|
|
|
|
static constexpr auto kNoteFFlagsMask = 0x00ffffff;
|
|
|
|
|
static constexpr auto kNoteTrigger = 0x01000000;
|
2023-11-10 19:08:31 +01:00
|
|
|
|
|
|
|
|
// kEvFiltProc
|
|
|
|
|
static constexpr auto kNoteExit = 0x80000000;
|
|
|
|
|
static constexpr auto kNoteFork = 0x40000000;
|
|
|
|
|
static constexpr auto kNoteExec = 0x20000000;
|
2023-10-30 22:09:15 +01:00
|
|
|
} // namespace orbis
|
2023-07-12 03:20:28 +02:00
|
|
|
|
|
|
|
|
orbis::SysResult orbis::sys_kqueue(Thread *thread) {
|
|
|
|
|
auto queue = knew<KQueue>();
|
|
|
|
|
if (queue == nullptr) {
|
|
|
|
|
return ErrorCode::NOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-30 22:09:15 +01:00
|
|
|
auto fd = thread->tproc->fileDescriptors.insert(queue);
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, fd);
|
|
|
|
|
thread->retval[0] = fd;
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr<char> name,
|
|
|
|
|
sint flags) {
|
2023-10-30 22:09:15 +01:00
|
|
|
auto queue = knew<KQueue>();
|
|
|
|
|
if (queue == nullptr) {
|
|
|
|
|
return ErrorCode::NOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto fd = thread->tproc->fileDescriptors.insert(queue);
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, name, flags, fd);
|
|
|
|
|
thread->retval[0] = fd;
|
2023-07-12 03:20:28 +02:00
|
|
|
return {};
|
|
|
|
|
}
|
2023-07-03 13:10:16 +02:00
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
namespace orbis {
|
|
|
|
|
static SysResult keventChange(KQueue *kq, KEvent &change) {
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change.flags & kEvAdd) {
|
|
|
|
|
if (nodeIt == kq->notes.end()) {
|
2023-11-10 19:08:31 +01:00
|
|
|
KNote note{
|
|
|
|
|
.event = change,
|
|
|
|
|
.enabled = true,
|
2023-11-03 20:12:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
note.event.flags &= ~(kEvAdd | kEvDelete | kEvDisable | kEvEnable);
|
|
|
|
|
kq->notes.push_front(note);
|
|
|
|
|
nodeIt = kq->notes.begin();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nodeIt == kq->notes.end()) {
|
|
|
|
|
if (change.flags & kEvDelete) {
|
2023-11-10 19:08:31 +01:00
|
|
|
return {};
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return orbis::ErrorCode::NOENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change.flags & kEvDisable) {
|
|
|
|
|
nodeIt->enabled = false;
|
|
|
|
|
}
|
|
|
|
|
if (change.flags & kEvEnable) {
|
|
|
|
|
nodeIt->enabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change.filter == kEvFiltUser) {
|
|
|
|
|
auto fflags = 0;
|
|
|
|
|
switch (change.fflags & kNoteFFCtrlMask) {
|
2023-11-10 19:08:31 +01:00
|
|
|
case kNoteFFAnd:
|
|
|
|
|
fflags = nodeIt->event.fflags & change.fflags;
|
|
|
|
|
break;
|
|
|
|
|
case kNoteFFOr:
|
|
|
|
|
fflags = nodeIt->event.fflags | change.fflags;
|
|
|
|
|
break;
|
|
|
|
|
case kNoteFFCopy:
|
|
|
|
|
fflags = change.fflags;
|
|
|
|
|
break;
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
nodeIt->event.fflags =
|
|
|
|
|
(nodeIt->event.fflags & ~kNoteFFlagsMask) | (fflags & kNoteFFlagsMask);
|
2023-11-03 20:12:59 +01:00
|
|
|
|
|
|
|
|
if (change.fflags & kNoteTrigger) {
|
|
|
|
|
nodeIt->event.fflags |= kNoteTrigger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (change.flags & kEvClear) {
|
|
|
|
|
nodeIt->event.fflags &= ~kNoteTrigger;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
return {};
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2023-07-06 18:16:25 +02:00
|
|
|
orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd,
|
2023-07-12 03:20:28 +02:00
|
|
|
ptr<KEvent> changelist, sint nchanges,
|
|
|
|
|
ptr<KEvent> eventlist, sint nevents,
|
|
|
|
|
ptr<const timespec> timeout) {
|
2023-10-30 22:09:15 +01:00
|
|
|
// ORBIS_LOG_TODO(__FUNCTION__, fd, changelist, nchanges, eventlist, nevents,
|
|
|
|
|
// timeout);
|
|
|
|
|
Ref<File> kqf = thread->tproc->fileDescriptors.get(fd);
|
|
|
|
|
if (kqf == nullptr) {
|
|
|
|
|
return orbis::ErrorCode::BADF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto kq = dynamic_cast<KQueue *>(kqf.get());
|
|
|
|
|
|
|
|
|
|
if (kq == nullptr) {
|
|
|
|
|
return orbis::ErrorCode::BADF;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
{
|
|
|
|
|
std::lock_guard lock(kqf->mtx);
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (nchanges != 0) {
|
|
|
|
|
for (auto change : std::span(changelist, nchanges)) {
|
|
|
|
|
ORBIS_LOG_TODO(__FUNCTION__, change.ident, change.filter, change.flags,
|
|
|
|
|
change.fflags, change.data, change.udata);
|
|
|
|
|
|
|
|
|
|
if (auto result = keventChange(kq, change); result.value() != 0) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
if (nevents == 0) {
|
2023-11-10 19:08:31 +01:00
|
|
|
return {};
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
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;
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2023-10-30 22:09:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<KEvent> result;
|
|
|
|
|
result.reserve(nevents);
|
|
|
|
|
|
2023-11-03 20:12:59 +01:00
|
|
|
while (result.empty()) {
|
2023-11-10 19:08:31 +01:00
|
|
|
{
|
|
|
|
|
std::lock_guard lock(kqf->mtx);
|
|
|
|
|
for (auto it = kq->notes.begin(); it != kq->notes.end();) {
|
|
|
|
|
if (result.size() >= nevents) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
auto ¬e = *it;
|
2023-11-03 20:12:59 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (!note.enabled) {
|
|
|
|
|
++it;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-11-03 20:12:59 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (note.event.filter == kEvFiltUser) {
|
|
|
|
|
if ((note.event.fflags & kNoteTrigger) == 0) {
|
|
|
|
|
++it;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto event = note.event;
|
|
|
|
|
event.fflags &= kNoteFFlagsMask;
|
|
|
|
|
result.push_back(event);
|
|
|
|
|
} else if (note.event.filter == kEvFiltDisplay ||
|
|
|
|
|
note.event.filter == kEvFiltGraphicsCore) {
|
|
|
|
|
result.push_back(note.event);
|
|
|
|
|
} else if (note.event.filter == kEvFiltProc) {
|
|
|
|
|
// TODO
|
|
|
|
|
if (note.event.fflags & kNoteExec) {
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
|
|
|
note.event.data = 0;
|
|
|
|
|
result.push_back(note.event);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-11-03 20:12:59 +01:00
|
|
|
++it;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (note.event.flags & kEvOneshot) {
|
|
|
|
|
it = kq->notes.erase(it);
|
|
|
|
|
} else {
|
|
|
|
|
++it;
|
|
|
|
|
}
|
2023-11-03 20:12:59 +01:00
|
|
|
}
|
2023-11-10 19:08:31 +01:00
|
|
|
}
|
2023-10-30 22:09:15 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (!result.empty()) {
|
|
|
|
|
break;
|
2023-10-30 22:09:15 +01:00
|
|
|
}
|
2023-11-03 20:12:59 +01:00
|
|
|
|
2023-11-10 19:08:31 +01:00
|
|
|
if (timeoutPoint != clock::time_point::max()) {
|
2023-11-03 20:12:59 +01:00
|
|
|
if (clock::now() >= timeoutPoint) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-10-31 23:58:03 +01:00
|
|
|
}
|
2023-11-10 19:08:31 +01:00
|
|
|
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
2023-10-30 22:09:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::memcpy(eventlist, result.data(), result.size() * sizeof(KEvent));
|
|
|
|
|
thread->retval[0] = result.size();
|
2023-07-03 13:10:16 +02:00
|
|
|
return {};
|
|
|
|
|
}
|