[orbis-kernel] Make evf IPC-safe

This commit is contained in:
Ivan Chikish 2023-07-20 15:10:38 +03:00
parent 72185f0086
commit 1bf88f6fe8
4 changed files with 29 additions and 39 deletions

View file

@ -32,9 +32,6 @@ struct EventFlag final {
struct WaitingThread {
Thread *thread;
utils::shared_cv *cv;
std::uint64_t *patternSet;
bool *isCanceled;
std::uint64_t bitPattern;
std::uint8_t waitMode;
@ -70,10 +67,9 @@ struct EventFlag final {
: attrs(attrs), value(initPattern) {}
ErrorCode wait(Thread *thread, std::uint8_t waitMode,
std::uint64_t bitPattern, std::uint64_t *patternSet,
std::uint32_t *timeout);
std::uint64_t bitPattern, std::uint32_t *timeout);
ErrorCode tryWait(Thread *thread, std::uint8_t waitMode,
std::uint64_t bitPattern, std::uint64_t *patternSet);
std::uint64_t bitPattern);
std::size_t notify(NotifyType type, std::uint64_t bits);
std::size_t destroy() { return notify(NotifyType::Destroy, {}); }

View file

@ -4,13 +4,15 @@
#include "orbis-config.hpp"
#include "types.hpp"
#include "../utils/SharedCV.hpp"
#include "../utils/SharedMutex.hpp"
#include <thread>
namespace orbis {
struct Process;
struct Thread {
shared_mutex mtx;
utils::shared_mutex mtx;
utils::shared_cv sync_cv;
Process *tproc = nullptr;
uint64_t retval[2]{};
void *context{};

View file

@ -6,12 +6,7 @@
orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode,
std::uint64_t bitPattern,
std::uint64_t *patternSet,
std::uint32_t *timeout) {
utils::shared_cv cv;
bool isCanceled = false;
using namespace std::chrono;
steady_clock::time_point start{};
@ -34,29 +29,27 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode,
*timeout = 0;
};
// Use retval to pass information between threads
thread->retval[0] = 0; // resultPattern
thread->retval[1] = 0; // isCanceled
std::unique_lock lock(queueMtx);
while (true) {
if (isDeleted) {
return ErrorCode::ACCES;
}
if (isCanceled) {
if (thread->retval[1]) {
return ErrorCode::CANCELED;
}
auto waitingThread = WaitingThread{.thread = thread,
.cv = &cv,
.patternSet = patternSet,
.isCanceled = &isCanceled,
.bitPattern = bitPattern,
.waitMode = waitMode};
auto waitingThread = WaitingThread{
.thread = thread, .bitPattern = bitPattern, .waitMode = waitMode};
if (auto patValue = value.load(std::memory_order::relaxed);
waitingThread.test(patValue)) {
auto resultValue = waitingThread.applyClear(patValue);
value.store(resultValue, std::memory_order::relaxed);
if (patternSet != nullptr) {
*patternSet = resultValue;
}
thread->retval[0] = resultValue;
// Success
break;
}
@ -90,21 +83,21 @@ orbis::ErrorCode orbis::EventFlag::wait(Thread *thread, std::uint8_t waitMode,
waitingThreads[position] = waitingThread;
if (timeout) {
cv.wait(queueMtx, *timeout);
thread->sync_cv.wait(queueMtx, *timeout);
update_timeout();
continue;
}
cv.wait(queueMtx);
thread->sync_cv.wait(queueMtx);
}
// TODO: update thread state
return {};
}
orbis::ErrorCode orbis::EventFlag::tryWait(Thread *, std::uint8_t waitMode,
std::uint64_t bitPattern,
std::uint64_t *patternSet) {
orbis::ErrorCode orbis::EventFlag::tryWait(Thread *thread,
std::uint8_t waitMode,
std::uint64_t bitPattern) {
writer_lock lock(queueMtx);
if (isDeleted) {
@ -118,10 +111,7 @@ orbis::ErrorCode orbis::EventFlag::tryWait(Thread *, std::uint8_t waitMode,
waitingThread.test(patValue)) {
auto resultValue = waitingThread.applyClear(patValue);
value.store(resultValue, std::memory_order::relaxed);
if (patternSet != nullptr) {
*patternSet = resultValue;
}
thread->retval[0] = resultValue;
return {};
}
@ -146,16 +136,14 @@ std::size_t orbis::EventFlag::notify(NotifyType type, std::uint64_t bits) {
auto resultValue = thread->applyClear(patValue);
patValue = resultValue;
if (thread->patternSet != nullptr) {
*thread->patternSet = resultValue;
}
thread->thread->retval[0] = resultValue;
if (type == NotifyType::Cancel) {
*thread->isCanceled = true;
thread->thread->retval[1] = true;
}
// TODO: update thread state
// release wait on waiter thread
thread->cv->notify_one(queueMtx);
thread->thread->sync_cv.notify_one(queueMtx);
waitingThreadsCount.fetch_sub(1, std::memory_order::relaxed);
std::memmove(thread, thread + 1,

View file

@ -209,8 +209,8 @@ orbis::SysResult orbis::sys_evf_wait(Thread *thread, sint id,
std::uint32_t resultTimeout{};
std::uint64_t resultPattern{};
auto result = evf->wait(thread, mode, patternSet,
pPatternSet != nullptr ? &resultPattern : nullptr,
pTimeout != nullptr ? &resultTimeout : nullptr);
resultPattern = thread->retval[0];
ORBIS_LOG_NOTICE("sys_evf_wait wakeup", thread, resultPattern, resultTimeout);
@ -221,6 +221,9 @@ orbis::SysResult orbis::sys_evf_wait(Thread *thread, sint id,
if (pTimeout != nullptr) {
uwrite(pTimeout, (uint32_t)resultTimeout);
}
thread->retval[0] = 0;
thread->retval[1] = 0;
return result;
}
@ -242,13 +245,14 @@ orbis::SysResult orbis::sys_evf_trywait(Thread *thread, sint id,
}
std::uint64_t resultPattern{};
auto result = evf->tryWait(thread, mode, patternSet,
pPatternSet != nullptr ? &resultPattern : nullptr);
auto result = evf->tryWait(thread, mode, patternSet);
resultPattern = thread->retval[0];
if (pPatternSet != nullptr) {
uwrite(pPatternSet, (uint64_t)resultPattern);
}
thread->retval[0] = 0;
return result;
}
orbis::SysResult orbis::sys_evf_set(Thread *thread, sint id, uint64_t value) {