[orbis-kernel] implement pipe kevents

This commit is contained in:
DH 2023-11-13 23:02:23 +03:00
parent 0f86008b9b
commit 0a957b8785
12 changed files with 262 additions and 122 deletions

View file

@ -1,117 +1,12 @@
#pragma once
#include "file.hpp"
#include "orbis-config.hpp"
#include "note.hpp"
#include "utils/SharedCV.hpp"
#include "utils/SharedMutex.hpp"
#include <list>
#include <mutex>
#include <set>
namespace orbis {
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;
// 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;
// kEvFiltProc
static constexpr auto kNoteExit = 0x80000000;
static constexpr auto kNoteFork = 0x40000000;
static constexpr auto kNoteExec = 0x20000000;
struct KEvent {
uintptr_t ident;
sshort filter;
ushort flags;
uint fflags;
intptr_t data;
ptr<void> udata;
};
struct KQueue;
struct KNote {
shared_mutex mutex;
Ref<KQueue> queue;
KEvent event{};
bool enabled = true;
bool triggered = false;
void *linked = nullptr; // TODO: use Ref<>
~KNote();
};
struct KQueue : orbis::File {
shared_cv cv;
std::list<KNote, kallocator<KNote>> notes;
};
struct EventEmitter {
shared_mutex mutex;
std::set<KNote *, std::less<>, kallocator<KNote *>> notes;
void emit(uint noteId, intptr_t data = 0) {
std::lock_guard lock(mutex);
for (auto note : notes) {
if ((note->event.fflags & noteId) == 0) {
continue;
}
std::lock_guard lock(note->mutex);
if (note->triggered) {
continue;
}
note->triggered = true;
note->event.data = data;
note->queue->cv.notify_all(note->queue->mtx);
}
}
};
} // namespace orbis

View file

@ -2,6 +2,7 @@
#include "KernelAllocator.hpp"
#include "error/ErrorCode.hpp"
#include "note.hpp"
#include "stat.hpp"
#include "utils/Rc.hpp"
#include "utils/SharedMutex.hpp"
@ -44,6 +45,7 @@ struct FileOps {
struct File : RcBase {
shared_mutex mtx;
EventEmitter event;
const FileOps *ops = nullptr;
Ref<RcBase> device;
std::uint64_t nextOff = 0;

View file

@ -78,7 +78,7 @@ struct IpmiSession : RcBase {
EventFlag evf{0, 0};
shared_cv connectCv;
bool expectedOutput = false; // TODO: verify
bool connected = false; // TODO: implement more states
bool connected = false; // TODO: implement more states
sint connectionStatus{0};
};
@ -121,9 +121,8 @@ SysResult sysIpmiDestroySession(Thread *thread, ptr<uint> result, uint kid,
SysResult sysIpmiServerReceivePacket(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSendConnectResult(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSendConnectResult(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionRespondSync(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiSessionGetClientPid(Thread *thread, ptr<uint> result, uint kid,
@ -137,4 +136,13 @@ SysResult sysIpmiSessionGetUserData(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiServerGetName(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
SysResult sysIpmiClientPollEventFlag(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSessionWaitEventFlag(Thread *thread, ptr<uint> result,
uint kid, ptr<void> params,
uint64_t paramsSz);
SysResult sysIpmiSessionSetEventFlag(Thread *thread, ptr<uint> result, uint kid,
ptr<void> params, uint64_t paramsSz);
} // namespace orbis

View file

@ -0,0 +1,92 @@
#pragma once
#include "KernelAllocator.hpp"
#include "orbis-config.hpp"
#include "utils/SharedMutex.hpp"
#include <mutex>
#include <set>
namespace orbis {
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;
// 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;
// kEvFiltProc
static constexpr auto kNoteExit = 0x80000000;
static constexpr auto kNoteFork = 0x40000000;
static constexpr auto kNoteExec = 0x20000000;
struct KEvent {
uintptr_t ident;
sshort filter;
ushort flags;
uint fflags;
intptr_t data;
ptr<void> udata;
};
struct KQueue;
struct KNote {
shared_mutex mutex;
Ref<KQueue> queue;
KEvent event{};
bool enabled = true;
bool triggered = false;
void *linked = nullptr; // TODO: use Ref<>
~KNote();
};
struct EventEmitter {
shared_mutex mutex;
std::set<KNote *, std::less<>, kallocator<KNote *>> notes;
void emit(uint filter, uint fflags = 0, intptr_t data = 0);
};
} // namespace orbis

View file

@ -3,9 +3,12 @@
#include "KernelAllocator.hpp"
#include "file.hpp"
#include "utils/Rc.hpp"
#include "utils/SharedCV.hpp"
#include "utils/SharedMutex.hpp"
namespace orbis {
struct Pipe final : File {
shared_cv cv;
kvector<std::byte> data;
};

View file

@ -13,3 +13,26 @@ orbis::KNote::~KNote() {
proc->event.notes.erase(this);
}
}
void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) {
std::lock_guard lock(mutex);
for (auto note : notes) {
if (note->event.filter != filter) {
continue;
}
if (fflags != 0 && ((note->event.fflags & fflags) == 0)) {
continue;
}
std::lock_guard lock(note->mutex);
if (note->triggered) {
continue;
}
note->triggered = true;
note->event.data = data;
note->queue->cv.notify_all(note->queue->mtx);
}
}

View file

@ -704,3 +704,73 @@ orbis::SysResult orbis::sysIpmiServerGetName(Thread *thread, ptr<uint> result,
return uwrite<uint>(result, 0);
}
orbis::SysResult orbis::sysIpmiClientPollEventFlag(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
struct IpmiPollEventFlagParam {
uint64_t index;
uint64_t patternSet;
uint64_t mode;
ptr<uint64_t> pPatternSet;
};
static_assert(sizeof(IpmiPollEventFlagParam) == 0x20);
if (paramsSz != sizeof(IpmiPollEventFlagParam)) {
return ErrorCode::INVAL;
}
IpmiPollEventFlagParam _params;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiPollEventFlagParam>(params)));
auto client = thread->tproc->ipmiMap.get(kid).cast<IpmiClient>();
if (client == nullptr) {
return ErrorCode::INVAL;
}
ORBIS_LOG_TODO(__FUNCTION__, client->name, _params.index, _params.patternSet, _params.mode, _params.pPatternSet);
ORBIS_RET_ON_ERROR(uwrite(_params.pPatternSet, 0u));
// client->evf.set(_params.a);
return ErrorCode::BUSY;
}
orbis::SysResult orbis::sysIpmiSessionWaitEventFlag(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
ORBIS_LOG_TODO(__FUNCTION__, paramsSz);
thread->where();
return uwrite<uint>(result, 0);
}
orbis::SysResult orbis::sysIpmiSessionSetEventFlag(Thread *thread,
ptr<uint> result, uint kid,
ptr<void> params,
uint64_t paramsSz) {
struct IpmiSetEventFlagParam {
uint64_t patternSet;
uint64_t index;
};
static_assert(sizeof(IpmiSetEventFlagParam) == 0x10);
if (paramsSz != sizeof(IpmiSetEventFlagParam)) {
return ErrorCode::INVAL;
}
IpmiSetEventFlagParam _params;
ORBIS_RET_ON_ERROR(uread(_params, ptr<IpmiSetEventFlagParam>(params)));
auto session = thread->tproc->ipmiMap.get(kid).cast<IpmiSession>();
if (session == nullptr) {
return ErrorCode::INVAL;
}
ORBIS_LOG_TODO(__FUNCTION__, session->client->name, _params.patternSet, _params.index);
session->evf.set(_params.patternSet);
return uwrite<uint>(result, 0);
}

View file

@ -3,17 +3,13 @@
#include "file.hpp"
#include "uio.hpp"
#include <span>
#include <thread>
static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio,
orbis::Thread *thread) {
auto pipe = static_cast<orbis::Pipe *>(file);
while (true) {
if (pipe->data.empty()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
if (pipe->data.empty()) {
pipe->cv.wait(file->mtx);
continue;
}
@ -33,6 +29,8 @@ static orbis::ErrorCode pipe_read(orbis::File *file, orbis::Uio *uio,
break;
}
file->event.emit(orbis::kEvFiltWrite);
return {};
}
@ -45,6 +43,9 @@ static orbis::ErrorCode pipe_write(orbis::File *file, orbis::Uio *uio,
pipe->data.resize(offset + vec.len);
std::memcpy(pipe->data.data(), vec.base, vec.len);
}
file->event.emit(orbis::kEvFiltRead);
pipe->cv.notify_one(file->mtx);
uio->resid = 0;
return {};
}

View file

@ -34,7 +34,7 @@ orbis::SysResult orbis::sys_kqueueex(Thread *thread, ptr<char> name,
}
namespace orbis {
static SysResult keventChange(KQueue *kq, KEvent &change) {
static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) {
auto nodeIt = kq->notes.end();
for (auto it = kq->notes.begin(); it != kq->notes.end(); ++it) {
if (it->event.ident == change.ident && it->event.filter == change.filter) {
@ -73,6 +73,22 @@ static SysResult keventChange(KQueue *kq, KEvent &change) {
std::unique_lock lock(process->event.mutex);
process->event.notes.insert(&*nodeIt);
nodeIt->linked = process;
} else if (change.filter == kEvFiltRead ||
change.filter == kEvFiltWrite) {
auto fd = thread->tproc->fileDescriptors.get(change.ident);
if (fd == nullptr) {
return ErrorCode::BADF;
}
std::unique_lock lock(fd->event.mutex);
if (change.filter == kEvFiltWrite) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
fd->event.notes.insert(&*nodeIt);
}
}
}
@ -121,7 +137,7 @@ static SysResult keventChange(KQueue *kq, KEvent &change) {
kq->cv.notify_all(kq->mtx);
}
} else if (change.filter == kEvFiltGraphicsCore ||
change.filter == kEvFiltDisplay) {
change.filter == kEvFiltDisplay || change.filter == kEvFiltRegEv) {
nodeIt->triggered = true;
kq->cv.notify_all(kq->mtx);
}
@ -163,7 +179,8 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd,
ORBIS_LOG_TODO(__FUNCTION__, change.ident, change.filter, change.flags,
change.fflags, change.data, change.udata);
if (auto result = keventChange(kq.get(), change); result.value() != 0) {
if (auto result = keventChange(kq.get(), change, thread);
result.value() != 0) {
return result;
}
}
@ -208,10 +225,15 @@ orbis::SysResult orbis::sys_kevent(Thread *thread, sint fd,
}
auto &note = *it;
std::lock_guard lock(note.mutex);
if (note.enabled && note.triggered) {
result.push_back(note.event);
if (note.event.flags & kEvDispatch) {
note.enabled = false;
}
if (note.event.flags & kEvOneshot) {
it = kq->notes.erase(it);
continue;

View file

@ -1107,6 +1107,10 @@ orbis::SysResult orbis::sys_ipmimgr_call(Thread *thread, uint op, uint kid,
return sysIpmiSessionGetUserData(thread, result, kid, params, paramsSz);
case 0x46a:
return sysIpmiServerGetName(thread, result, kid, params, paramsSz);
case 0x491:
return sysIpmiClientPollEventFlag(thread, result, kid, params, paramsSz);
case 0x493:
return sysIpmiSessionSetEventFlag(thread, result, kid, params, paramsSz);
}
ORBIS_LOG_TODO(__FUNCTION__, thread->tid, op, kid, result, params, paramsSz);

View file

@ -1,5 +1,6 @@
#include "pipe.hpp"
#include "sys/sysproto.hpp"
#include "uio.hpp"
#include "utils/Logs.hpp"
#include <chrono>
#include <sys/socket.h>
@ -68,7 +69,26 @@ orbis::SysResult orbis::sys_recvfrom(Thread *thread, sint s, caddr_t buf,
size_t len, sint flags,
ptr<struct sockaddr> from,
ptr<uint32_t> fromlenaddr) {
return ErrorCode::NOSYS;
auto pipe = thread->tproc->fileDescriptors.get(s).cast<Pipe>();
if (pipe == nullptr) {
return ErrorCode::INVAL;
}
std::lock_guard lock(pipe->mtx);
IoVec io = {
.base = buf,
.len = len,
};
Uio uio{
.iov = &io,
.iovcnt = 1,
.segflg = UioSeg::UserSpace,
.rw = UioRw::Read,
.td = thread,
};
pipe->ops->read(pipe.get(), &uio, thread);
thread->retval[0] = uio.offset;
return {};
}
orbis::SysResult orbis::sys_recvmsg(Thread *thread, sint s,
ptr<struct msghdr> msg, sint flags) {

View file

@ -641,7 +641,7 @@ orbis::SysResult nmount(orbis::Thread *thread, orbis::ptr<orbis::IoVec> iovp,
orbis::SysResult exit(orbis::Thread *thread, orbis::sint status) {
std::printf("Requested exit with status %d\n", status);
thread->tproc->event.emit(orbis::kNoteExit, status);
thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExit, status);
std::exit(status);
}
@ -706,7 +706,7 @@ SysResult fork(Thread *thread, slong flags) {
kfree(flag, sizeof(*flag));
thread->tproc->event.emit(orbis::kNoteFork, childPid);
thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteFork, childPid);
thread->retval[0] = childPid;
thread->retval[1] = 0;
return {};
@ -828,7 +828,7 @@ SysResult execve(Thread *thread, ptr<char> fname, ptr<ptr<char>> argv,
thread->tproc->processParam = executableModule->processParam;
thread->tproc->processParamSize = executableModule->processParamSize;
thread->tproc->event.emit(orbis::kNoteExec);
thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec);
ORBIS_LOG_ERROR(__FUNCTION__, "done");
std::thread([&] {