From acf32f841ceac58b373fb0b7dad0f72cc9f45a70 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Mon, 12 Nov 2018 12:30:58 +0100 Subject: [PATCH] meso: Implement LightSession functions --- .../processes/KLightClientSession.hpp | 4 + .../processes/KLightServerSession.hpp | 12 +- .../mesosphere/processes/KLightSession.hpp | 5 + .../include/mesosphere/threading/KThread.hpp | 20 +++ mesosphere/source/interrupts/KAlarm.cpp | 5 +- .../source/processes/KLightClientSession.cpp | 13 +- .../source/processes/KLightServerSession.cpp | 117 ++++++++++++++++-- mesosphere/source/threading/KThread.cpp | 19 +++ 8 files changed, 177 insertions(+), 18 deletions(-) diff --git a/mesosphere/include/mesosphere/processes/KLightClientSession.hpp b/mesosphere/include/mesosphere/processes/KLightClientSession.hpp index 2366718eb..cac4b620a 100644 --- a/mesosphere/include/mesosphere/processes/KLightClientSession.hpp +++ b/mesosphere/include/mesosphere/processes/KLightClientSession.hpp @@ -11,12 +11,16 @@ namespace mesosphere class KLightSession; class KClientPort; +struct LightSessionRequest; + class KLightClientSession final : public KAutoObject, public IClient { public: MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightClientSession); virtual ~KLightClientSession(); + Result SendSyncRequest(LightSessionRequest *request); + private: friend class KLightSession; diff --git a/mesosphere/include/mesosphere/processes/KLightServerSession.hpp b/mesosphere/include/mesosphere/processes/KLightServerSession.hpp index c481f5fae..78f2b2226 100644 --- a/mesosphere/include/mesosphere/processes/KLightServerSession.hpp +++ b/mesosphere/include/mesosphere/processes/KLightServerSession.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -15,17 +15,19 @@ class KLightClientSession; class KLightSession; class KClientPort; +struct LightSessionRequest; + struct LightServerSessionListTag; using LightServerSessionListBaseHook = boost::intrusive::list_base_hook >; class KLightServerSession final : - public KSynchronizationObject, + public KAutoObject, public IServer, public LightServerSessionListBaseHook { public: - MESOSPHERE_AUTO_OBJECT_TRAITS(SynchronizationObject, LightServerSession); + MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightServerSession); using List = typename boost::intrusive::make_list< KLightServerSession, @@ -35,8 +37,10 @@ class KLightServerSession final : virtual ~KLightServerSession(); - virtual bool IsSignaled() const override; + /// Needs to be called from critical section + Result HandleSyncRequest(KThread &sender); + Result ReplyAndReceive(LightSessionRequest *request); private: friend class KLightSession; diff --git a/mesosphere/include/mesosphere/processes/KLightSession.hpp b/mesosphere/include/mesosphere/processes/KLightSession.hpp index d80860682..9e68530f6 100644 --- a/mesosphere/include/mesosphere/processes/KLightSession.hpp +++ b/mesosphere/include/mesosphere/processes/KLightSession.hpp @@ -11,6 +11,11 @@ namespace mesosphere { +struct LightSessionRequest { + s32 cmdId; + u32 data[6]; +}; + class KLightSession final : public KAutoObject, public ISetAllocated, diff --git a/mesosphere/include/mesosphere/threading/KThread.hpp b/mesosphere/include/mesosphere/threading/KThread.hpp index be7749eed..475ef05dc 100644 --- a/mesosphere/include/mesosphere/threading/KThread.hpp +++ b/mesosphere/include/mesosphere/threading/KThread.hpp @@ -13,6 +13,8 @@ namespace mesosphere { +struct LightSessionRequest; + struct KThreadContext; struct ThreadWaitListTag; @@ -236,8 +238,12 @@ class KThread final : bool WaitForKernelSync(WaitList &waitList); /// Takes effect when critical section is left void ResumeFromKernelSync(); + /// Takes effect when critical section is left + void ResumeFromKernelSync(Result res); /// Takes effect when critical section is left -- all threads in waitlist static void ResumeAllFromKernelSync(WaitList &waitList); + /// Takes effect when critical section is left -- all threads in waitlist + static void ResumeAllFromKernelSync(WaitList &waitList, Result res); /// Takes effect immediately void CancelKernelSync(); /// Takes effect immediately @@ -250,10 +256,23 @@ class KThread final : void SetWaitingSync(bool isWaitingSync) { this->isWaitingSync = isWaitingSync; } constexpr bool IsSyncCancelled() const { return isSyncCancelled; } void SetSyncCancelled(bool isSyncCancelled) { this->isSyncCancelled = isSyncCancelled; } + void ClearSync() + { + signaledSyncObject = nullptr; + syncResult = ResultSuccess(); + } + + constexpr Result GetSyncResult() const { return syncResult; } /// Takes effect when critical section is left void HandleSyncObjectSignaled(KSynchronizationObject *syncObj); + LightSessionRequest *GetCurrentLightSessionRequest() const { return currentLightSessionRequest; } + void SetCurrentLightSessionRequest(LightSessionRequest *currentLightSessionRequest) + { + this->currentLightSessionRequest = currentLightSessionRequest; + } + template Result WaitSynchronization(int &outId, KSynchronizationObject **syncObjs, int numSyncObjs, const std::chrono::time_point &timeoutTime) { @@ -305,6 +324,7 @@ private: ulong affinityMask = 0; bool isSyncCancelled = false; bool isWaitingSync = false; + LightSessionRequest *currentLightSessionRequest = nullptr; // located in kernel thread stacks uiptr wantedMutex = 0; KThread *wantedMutexOwner = nullptr; MutexWaitList mutexWaitList{}; diff --git a/mesosphere/source/interrupts/KAlarm.cpp b/mesosphere/source/interrupts/KAlarm.cpp index 14f1d13d6..7524ef4a2 100644 --- a/mesosphere/source/interrupts/KAlarm.cpp +++ b/mesosphere/source/interrupts/KAlarm.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include namespace mesosphere @@ -24,8 +24,7 @@ void KAlarm::RemoveAlarmable(const IAlarmable &alarmable) void KAlarm::HandleAlarm() { { - KCriticalSection &critsec = KScheduler::GetCriticalSection(); - std::scoped_lock criticalSection{critsec}; + KScopedCriticalSection critsec{}; std::scoped_lock guard{spinlock}; KSystemClock::SetInterruptMasked(true); // mask timer interrupt diff --git a/mesosphere/source/processes/KLightClientSession.cpp b/mesosphere/source/processes/KLightClientSession.cpp index 05a480633..35154e61e 100644 --- a/mesosphere/source/processes/KLightClientSession.cpp +++ b/mesosphere/source/processes/KLightClientSession.cpp @@ -1,6 +1,7 @@ -#include #include #include +#include +#include namespace mesosphere { @@ -10,5 +11,15 @@ KLightClientSession::~KLightClientSession() parent->Terminate(false); } +Result KLightClientSession::SendSyncRequest(LightSessionRequest *request) +{ + KScopedCriticalSection critsec{}; + Result res; + KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread(); + curThread->SetCurrentLightSessionRequest(request); + curThread->ClearSync(); + res = parent->server.HandleSyncRequest(*curThread); + return res.IsSuccess() ? curThread->GetSyncResult() : res; +} } diff --git a/mesosphere/source/processes/KLightServerSession.cpp b/mesosphere/source/processes/KLightServerSession.cpp index 481278e7d..ef294c1e2 100644 --- a/mesosphere/source/processes/KLightServerSession.cpp +++ b/mesosphere/source/processes/KLightServerSession.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include namespace mesosphere { @@ -10,11 +10,6 @@ KLightServerSession::~KLightServerSession() Terminate(true); } -bool KLightServerSession::IsSignaled() const -{ - return false; // TODO -} - void KLightServerSession::Terminate(bool fromServer) { SharedPtr curSender{std::move(currentSender)}; @@ -26,19 +21,121 @@ void KLightServerSession::Terminate(bool fromServer) parent->isClientAlive = false; } if (curSender != nullptr) { - kassert(curSender->GetSchedulingStatus() == KThread::SchedulingStatus::Paused && curSender->IsInKernelSync()); - curSender->CancelKernelSync(ResultKernelConnectionClosed()); //TODO check + if (!curSender->IsDying()) { + curSender->ResumeFromKernelSync(ResultKernelConnectionClosed()); + } currentSender = nullptr; currentReceiver = nullptr; } for (auto &&sender : senderThreads) { - kassert(sender.GetSchedulingStatus() == KThread::SchedulingStatus::Paused && sender.IsInKernelSync()); - sender.CancelKernelSync(ResultKernelConnectionClosed()); //TODO check + if (!sender.IsDying()) { + sender.ResumeFromKernelSync(ResultKernelConnectionClosed()); //TODO check + } } KThread::ResumeAllFromKernelSync(receiverThreads); } } +Result KLightServerSession::HandleSyncRequest(KThread &sender) +{ + if (!parent->isClientAlive || !parent->isServerAlive) { + return ResultKernelConnectionClosed(); + } + + if (!sender.WaitForKernelSync(senderThreads)) { + return ResultKernelThreadTerminating(); + } + + if (currentSender != nullptr || receiverThreads.empty()) { + // Nothing more to do if a request is being handled or if there's no receiver yet. + return ResultSuccess(); + } else { + // Otherwise, wake once receiver. + receiverThreads.front().ResumeFromKernelSync(); + return ResultSuccess(); + } +} + +Result KLightServerSession::ReplyAndReceive(LightSessionRequest *request) +{ + KThread *curThread = KCoreContext::GetCurrentInstance().GetCurrentThread(); + curThread->SetCurrentLightSessionRequest(request); + + if (request->cmdId < 0) { + // Reply + SharedPtr curSender{}; + { + KScopedCriticalSection critsec{}; + if (!parent->isClientAlive || !parent->isServerAlive) { + return ResultKernelConnectionClosed(); + } + if (currentSender == nullptr || currentReceiver != curThread) { + return ResultKernelInvalidState(); + } + + curSender = std::move(currentSender); + if (!curSender->IsDying()) { + *curSender->GetCurrentLightSessionRequest() = *curThread->GetCurrentLightSessionRequest(); + curSender->ResumeFromKernelSync(); + } + currentSender = nullptr; + currentReceiver = nullptr; + } + } + + { + // Receive + KCriticalSection &critsec = KScheduler::GetCriticalSection(); + std::scoped_lock criticalSection{critsec}; + bool waitedForSync = false; + + // If there's already one receiver, return an error + if (!receiverThreads.empty()) { + return ResultKernelInvalidState(); + } + + while (currentReceiver == nullptr) { + if (waitedForSync) { + curThread->SetWaitingSync(false); + } + + if (!parent->isClientAlive || !parent->isServerAlive) { + return ResultKernelConnectionClosed(); + } + + // Try to see if we can do sync immediately, otherwise wait until later... + if (currentSender == nullptr && !senderThreads.empty()) { + // Do the sync. + currentSender = &senderThreads.front(); + currentReceiver = curThread; + *curThread->GetCurrentLightSessionRequest() = *currentSender->GetCurrentLightSessionRequest(); + return ResultSuccess(); + } else { + // We didn't get to sync, we need to wait. + if (!curThread->WaitForKernelSync(receiverThreads)) { + return ResultKernelThreadTerminating(); + } + + if (curThread->IsSyncCancelled()) { + curThread->ResumeFromKernelSync(); + curThread->SetSyncCancelled(false); + return ResultKernelCancelled(); + } + + // Wait NOW. + critsec.unlock(); + critsec.lock(); + waitedForSync = true; + if (receiverThreads.empty()) { + return ResultKernelInvalidState(); + } + } + } + } + + return ResultKernelInvalidState(); +} + } diff --git a/mesosphere/source/threading/KThread.cpp b/mesosphere/source/threading/KThread.cpp index 775684a77..83588a34a 100644 --- a/mesosphere/source/threading/KThread.cpp +++ b/mesosphere/source/threading/KThread.cpp @@ -85,6 +85,13 @@ void KThread::ResumeFromKernelSync() Reschedule(SchedulingStatus::Running); } +void KThread::ResumeFromKernelSync(Result res) +{ + // Has to be called from critical section + syncResult = res; + ResumeFromKernelSync(); +} + void KThread::ResumeAllFromKernelSync(KThread::WaitList &waitList) { // Has to be called from critical section @@ -96,6 +103,18 @@ void KThread::ResumeAllFromKernelSync(KThread::WaitList &waitList) ); } +void KThread::ResumeAllFromKernelSync(KThread::WaitList &waitList, Result res) +{ + // Has to be called from critical section + waitList.clear_and_dispose( + [res](KThread *t) { + t->syncResult = res; + t->currentWaitList = nullptr; + t->Reschedule(SchedulingStatus::Running); + } + ); + +} void KThread::CancelKernelSync() { KScopedCriticalSection criticalSection;