mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
meso: Implement LightSession functions
This commit is contained in:
parent
be3550d382
commit
acf32f841c
8 changed files with 177 additions and 18 deletions
|
@ -11,12 +11,16 @@ namespace mesosphere
|
|||
class KLightSession;
|
||||
class KClientPort;
|
||||
|
||||
struct LightSessionRequest;
|
||||
|
||||
class KLightClientSession final : public KAutoObject, public IClient<KLightSession, KLightClientSession, KLightServerSession> {
|
||||
public:
|
||||
MESOSPHERE_AUTO_OBJECT_TRAITS(AutoObject, LightClientSession);
|
||||
|
||||
virtual ~KLightClientSession();
|
||||
|
||||
Result SendSyncRequest(LightSessionRequest *request);
|
||||
|
||||
private:
|
||||
friend class KLightSession;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <mesosphere/core/util.hpp>
|
||||
#include <mesosphere/core/Result.hpp>
|
||||
#include <mesosphere/core/KSynchronizationObject.hpp>
|
||||
#include <mesosphere/core/KAutoObject.hpp>
|
||||
#include <mesosphere/interfaces/IServer.hpp>
|
||||
#include <mesosphere/threading/KThread.hpp>
|
||||
|
||||
|
@ -15,17 +15,19 @@ class KLightClientSession;
|
|||
class KLightSession;
|
||||
class KClientPort;
|
||||
|
||||
struct LightSessionRequest;
|
||||
|
||||
struct LightServerSessionListTag;
|
||||
using LightServerSessionListBaseHook = boost::intrusive::list_base_hook<boost::intrusive::tag<LightServerSessionListTag> >;
|
||||
|
||||
class KLightServerSession final :
|
||||
public KSynchronizationObject,
|
||||
public KAutoObject,
|
||||
public IServer<KLightSession, KLightClientSession, KLightServerSession>,
|
||||
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;
|
||||
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
namespace mesosphere
|
||||
{
|
||||
|
||||
struct LightSessionRequest {
|
||||
s32 cmdId;
|
||||
u32 data[6];
|
||||
};
|
||||
|
||||
class KLightSession final :
|
||||
public KAutoObject,
|
||||
public ISetAllocated<KLightSession>,
|
||||
|
|
|
@ -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<typename Clock, typename Duration>
|
||||
Result WaitSynchronization(int &outId, KSynchronizationObject **syncObjs, int numSyncObjs, const std::chrono::time_point<Clock, Duration> &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{};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <mesosphere/interrupts/KAlarm.hpp>
|
||||
#include <mesosphere/threading/KScheduler.hpp>
|
||||
#include <mesosphere/threading/KScopedCriticalSection.hpp>
|
||||
#include <mesosphere/arch/KInterruptMaskGuard.hpp>
|
||||
|
||||
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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <mesosphere/processes/KLightClientSession.hpp>
|
||||
#include <mesosphere/processes/KLightSession.hpp>
|
||||
#include <mesosphere/threading/KScopedCriticalSection.hpp>
|
||||
#include <mesosphere/threading/KThread.hpp>
|
||||
#include <mesosphere/core/KCoreContext.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <mesosphere/processes/KLightServerSession.hpp>
|
||||
#include <mesosphere/processes/KLightSession.hpp>
|
||||
#include <mesosphere/threading/KScopedCriticalSection.hpp>
|
||||
#include <mesosphere/core/KCoreContext.hpp>
|
||||
|
||||
namespace mesosphere
|
||||
{
|
||||
|
@ -10,11 +10,6 @@ KLightServerSession::~KLightServerSession()
|
|||
Terminate(true);
|
||||
}
|
||||
|
||||
bool KLightServerSession::IsSignaled() const
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
void KLightServerSession::Terminate(bool fromServer)
|
||||
{
|
||||
SharedPtr<KThread> 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<KThread> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue