mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-15 03:27:49 +01:00
kern: correct behavior when setting activity/core mask for pinned thread
This commit is contained in:
parent
787964f7e7
commit
f70ee67753
@ -47,7 +47,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
MESOSPHERE_LOG("SP = %016lx\n", context->sp);
|
MESOSPHERE_LOG("SP = %016lx\n", context->sp);
|
||||||
|
|
||||||
/* Dump the page tables. */
|
/* Dump the page tables. */
|
||||||
GetCurrentProcess().GetPageTable().DumpTable();
|
/* GetCurrentProcess().GetPageTable().DumpTable(); */
|
||||||
|
|
||||||
MESOSPHERE_PANIC("Unhandled Exception in User Mode\n");
|
MESOSPHERE_PANIC("Unhandled Exception in User Mode\n");
|
||||||
|
|
||||||
|
@ -555,8 +555,10 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(this->parent != nullptr);
|
MESOSPHERE_ASSERT(this->parent != nullptr);
|
||||||
MESOSPHERE_ASSERT(affinity_mask != 0);
|
MESOSPHERE_ASSERT(affinity_mask != 0);
|
||||||
|
KScopedLightLock lk(this->activity_pause_lock);
|
||||||
|
|
||||||
|
/* Set the core mask. */
|
||||||
{
|
{
|
||||||
KScopedLightLock lk(this->activity_pause_lock);
|
|
||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0);
|
MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0);
|
||||||
|
|
||||||
@ -598,7 +600,59 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Paused waiter list. */
|
/* Update the pinned waiter list. */
|
||||||
|
{
|
||||||
|
bool retry_update;
|
||||||
|
bool thread_is_pinned = false;
|
||||||
|
do {
|
||||||
|
/* Lock the scheduler. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
/* Don't do any further management if our termination has been requested. */
|
||||||
|
R_SUCCEED_IF(this->IsTerminationRequested());
|
||||||
|
|
||||||
|
/* By default, we won't need to retry. */
|
||||||
|
retry_update = false;
|
||||||
|
|
||||||
|
/* Check if the thread is currently running. */
|
||||||
|
bool thread_is_current = false;
|
||||||
|
s32 thread_core;
|
||||||
|
for (thread_core = 0; thread_core < static_cast<s32>(cpu::NumCores); ++thread_core) {
|
||||||
|
if (Kernel::GetCurrentContext(thread_core).current_thread == this) {
|
||||||
|
thread_is_current = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the thread is currently running, check whether it's no longer allowed under the new mask. */
|
||||||
|
if (thread_is_current && ((1ul << thread_core) & affinity_mask) == 0) {
|
||||||
|
/* If the thread is pinned, we want to wait until it's not pinned. */
|
||||||
|
if (this->GetStackParameters().is_pinned) {
|
||||||
|
/* Verify that the current thread isn't terminating. */
|
||||||
|
R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested());
|
||||||
|
|
||||||
|
/* Note that the thread was pinned. */
|
||||||
|
thread_is_pinned = true;
|
||||||
|
|
||||||
|
/* Wait until the thread isn't pinned any more. */
|
||||||
|
this->pinned_waiter_list.push_back(GetCurrentThread());
|
||||||
|
GetCurrentThread().SetState(ThreadState_Waiting);
|
||||||
|
} else {
|
||||||
|
/* If the thread isn't pinned, release the scheduler lock and retry until it's not current. */
|
||||||
|
retry_update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (retry_update);
|
||||||
|
|
||||||
|
/* If the thread was pinned, it no longer is, and we should remove the current thread from our waiter list. */
|
||||||
|
if (thread_is_pinned) {
|
||||||
|
/* Lock the scheduler. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
/* Remove from the list. */
|
||||||
|
this->pinned_waiter_list.erase(this->pinned_waiter_list.iterator_to(GetCurrentThread()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
@ -720,32 +774,81 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result KThread::SetActivity(ams::svc::ThreadActivity activity) {
|
Result KThread::SetActivity(ams::svc::ThreadActivity activity) {
|
||||||
/* Lock ourselves and the scheduler. */
|
/* Lock ourselves. */
|
||||||
KScopedLightLock lk(this->activity_pause_lock);
|
KScopedLightLock lk(this->activity_pause_lock);
|
||||||
KScopedSchedulerLock sl;
|
|
||||||
|
|
||||||
/* Verify our state. */
|
/* Set the activity. */
|
||||||
const auto cur_state = this->GetState();
|
{
|
||||||
R_UNLESS((cur_state == ThreadState_Waiting || cur_state == ThreadState_Runnable), svc::ResultInvalidState());
|
/* Lock the scheduler. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
/* Either pause or resume. */
|
/* Verify our state. */
|
||||||
|
const auto cur_state = this->GetState();
|
||||||
|
R_UNLESS((cur_state == ThreadState_Waiting || cur_state == ThreadState_Runnable), svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Either pause or resume. */
|
||||||
|
if (activity == ams::svc::ThreadActivity_Paused) {
|
||||||
|
/* Verify that we're not suspended. */
|
||||||
|
R_UNLESS(!this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Suspend. */
|
||||||
|
this->RequestSuspend(SuspendType_Thread);
|
||||||
|
} else {
|
||||||
|
MESOSPHERE_ASSERT(activity == ams::svc::ThreadActivity_Runnable);
|
||||||
|
|
||||||
|
/* Verify that we're suspended. */
|
||||||
|
R_UNLESS(this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Resume. */
|
||||||
|
this->Resume(SuspendType_Thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the thread is now paused, update the pinned waiter list. */
|
||||||
if (activity == ams::svc::ThreadActivity_Paused) {
|
if (activity == ams::svc::ThreadActivity_Paused) {
|
||||||
/* Verify that we're not suspended. */
|
bool thread_is_pinned = false;
|
||||||
R_UNLESS(!this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState());
|
bool thread_is_current;
|
||||||
|
do {
|
||||||
|
/* Lock the scheduler. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
/* Suspend. */
|
/* Don't do any further management if our termination has been requested. */
|
||||||
this->RequestSuspend(SuspendType_Thread);
|
R_SUCCEED_IF(this->IsTerminationRequested());
|
||||||
|
|
||||||
/* TODO: Paused waiter list. */
|
/* Check whether the thread is pinned. */
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
if (this->GetStackParameters().is_pinned) {
|
||||||
} else {
|
/* Verify that the current thread isn't terminating. */
|
||||||
MESOSPHERE_ASSERT(activity == ams::svc::ThreadActivity_Runnable);
|
R_UNLESS(!GetCurrentThread().IsTerminationRequested(), svc::ResultTerminationRequested());
|
||||||
|
|
||||||
/* Verify that we're suspended. */
|
/* Note that the thread was pinned and not current. */
|
||||||
R_UNLESS(this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState());
|
thread_is_pinned = true;
|
||||||
|
thread_is_current = false;
|
||||||
|
|
||||||
/* Resume. */
|
/* Wait until the thread isn't pinned any more. */
|
||||||
this->Resume(SuspendType_Thread);
|
this->pinned_waiter_list.push_back(GetCurrentThread());
|
||||||
|
GetCurrentThread().SetState(ThreadState_Waiting);
|
||||||
|
} else {
|
||||||
|
/* Check if the thread is currently running. */
|
||||||
|
/* If it is, we'll need to retry. */
|
||||||
|
thread_is_current = false;
|
||||||
|
|
||||||
|
for (auto i = 0; i < static_cast<s32>(cpu::NumCores); ++i) {
|
||||||
|
if (Kernel::GetCurrentContext(i).current_thread == this) {
|
||||||
|
thread_is_current = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (thread_is_current);
|
||||||
|
|
||||||
|
/* If the thread was pinned, it no longer is, and we should remove the current thread from our waiter list. */
|
||||||
|
if (thread_is_pinned) {
|
||||||
|
/* Lock the scheduler. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
/* Remove from the list. */
|
||||||
|
this->pinned_waiter_list.erase(this->pinned_waiter_list.iterator_to(GetCurrentThread()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
|
Loading…
Reference in New Issue
Block a user