aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/process.cpp')
-rw-r--r--src/core/hle/kernel/process.cpp210
1 files changed, 127 insertions, 83 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b905b486a..47b3ac57b 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -14,15 +14,16 @@
#include "core/device_memory.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/code_set.h"
-#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory/memory_block_manager.h"
#include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/memory/slab_heap.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
-#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/svc_results.h"
#include "core/hle/lock.h"
#include "core/memory.h"
#include "core/settings.h"
@@ -38,11 +39,11 @@ namespace {
*/
void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
- ThreadType type = THREADTYPE_USER;
- auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0,
- owner_process.GetIdealCore(), stack_top, &owner_process);
+ ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
+ auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
+ owner_process.GetIdealCoreId(), stack_top, &owner_process);
- std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
+ std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
// Register 1 must be a handle to the main thread
const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
@@ -55,7 +56,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority,
// Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
{
KScopedSchedulerLock lock{kernel};
- thread->SetStatus(ThreadStatus::Ready);
+ thread->SetState(ThreadState::Runnable);
}
}
} // Anonymous namespace
@@ -117,7 +118,10 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name);
- process->resource_limit = ResourceLimit::Create(kernel);
+
+ // TODO: This is inaccurate
+ // The process should hold a reference to the kernel-wide resource limit.
+ process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -133,12 +137,32 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
return process;
}
-std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
+std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
return resource_limit;
}
+void Process::IncrementThreadCount() {
+ ASSERT(num_threads >= 0);
+ num_created_threads++;
+
+ if (const auto count = ++num_threads; count > peak_num_threads) {
+ peak_num_threads = count;
+ }
+}
+
+void Process::DecrementThreadCount() {
+ ASSERT(num_threads > 0);
+
+ if (const auto count = --num_threads; count == 0) {
+ UNIMPLEMENTED_MSG("Process termination is not implemented!");
+ }
+}
+
u64 Process::GetTotalPhysicalMemoryAvailable() const {
- const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
+ // TODO: This is expected to always return the application memory pool size after accurately
+ // reserving kernel resources. The current workaround uses a process-local resource limit of
+ // application memory pool size, which is inaccurate.
+ const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
@@ -162,68 +186,79 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
}
-void Process::InsertConditionVariableThread(std::shared_ptr<Thread> thread) {
- VAddr cond_var_addr = thread->GetCondVarWaitAddress();
- std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread> current_thread = *it;
- if (current_thread->GetPriority() > thread->GetPriority()) {
- thread_list.insert(it, thread);
- return;
+bool Process::ReleaseUserException(KThread* thread) {
+ KScopedSchedulerLock sl{kernel};
+
+ if (exception_thread == thread) {
+ exception_thread = nullptr;
+
+ // Remove waiter thread.
+ s32 num_waiters{};
+ KThread* next = thread->RemoveWaiterByKey(
+ std::addressof(num_waiters),
+ reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
+ if (next != nullptr) {
+ if (next->GetState() == ThreadState::Waiting) {
+ next->SetState(ThreadState::Runnable);
+ } else {
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
+ }
}
- ++it;
+
+ return true;
+ } else {
+ return false;
}
- thread_list.push_back(thread);
}
-void Process::RemoveConditionVariableThread(std::shared_ptr<Thread> thread) {
- VAddr cond_var_addr = thread->GetCondVarWaitAddress();
- std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- const std::shared_ptr<Thread> current_thread = *it;
- if (current_thread.get() == thread.get()) {
- thread_list.erase(it);
- return;
- }
- ++it;
- }
+void Process::PinCurrentThread() {
+ ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+ // Get the current thread.
+ const s32 core_id = GetCurrentCoreId(kernel);
+ KThread* cur_thread = GetCurrentThreadPointer(kernel);
+
+ // Pin it.
+ PinThread(core_id, cur_thread);
+ cur_thread->Pin();
+
+ // An update is needed.
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
}
-std::vector<std::shared_ptr<Thread>> Process::GetConditionVariableThreads(
- const VAddr cond_var_addr) {
- std::vector<std::shared_ptr<Thread>> result{};
- std::list<std::shared_ptr<Thread>>& thread_list = cond_var_threads[cond_var_addr];
- auto it = thread_list.begin();
- while (it != thread_list.end()) {
- std::shared_ptr<Thread> current_thread = *it;
- result.push_back(current_thread);
- ++it;
- }
- return result;
+void Process::UnpinCurrentThread() {
+ ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+ // Get the current thread.
+ const s32 core_id = GetCurrentCoreId(kernel);
+ KThread* cur_thread = GetCurrentThreadPointer(kernel);
+
+ // Unpin it.
+ cur_thread->Unpin();
+ UnpinThread(core_id, cur_thread);
+
+ // An update is needed.
+ KScheduler::SetSchedulerUpdateNeeded(kernel);
}
-void Process::RegisterThread(const Thread* thread) {
+void Process::RegisterThread(const KThread* thread) {
thread_list.push_back(thread);
}
-void Process::UnregisterThread(const Thread* thread) {
+void Process::UnregisterThread(const KThread* thread) {
thread_list.remove(thread);
}
-ResultCode Process::ClearSignalState() {
- KScopedSchedulerLock lock(system.Kernel());
- if (status == ProcessStatus::Exited) {
- LOG_ERROR(Kernel, "called on a terminated process instance.");
- return ERR_INVALID_STATE;
- }
+ResultCode Process::Reset() {
+ // Lock the process and the scheduler.
+ KScopedLightLock lk(state_lock);
+ KScopedSchedulerLock sl{kernel};
- if (!is_signaled) {
- LOG_ERROR(Kernel, "called on a process instance that isn't signaled.");
- return ERR_INVALID_STATE;
- }
+ // Validate that we're in a state that we can reset.
+ R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
+ R_UNLESS(is_signaled, ResultInvalidState);
+ // Clear signaled.
is_signaled = false;
return RESULT_SUCCESS;
}
@@ -236,6 +271,17 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size;
+ // Set initial resource limits
+ resource_limit->SetLimitValue(
+ LimitableResource::PhysicalMemory,
+ kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
+ KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
+ code_size + system_resource_size);
+ if (!memory_reservation.Succeeded()) {
+ LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
+ code_size + system_resource_size);
+ return ResultResourceLimitedExceeded;
+ }
// Initialize proces address space
if (const ResultCode result{
page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000,
@@ -277,24 +323,22 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
UNREACHABLE();
}
- // Set initial resource limits
- resource_limit->SetLimitValue(
- ResourceType::PhysicalMemory,
- kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application));
- resource_limit->SetLimitValue(ResourceType::Threads, 608);
- resource_limit->SetLimitValue(ResourceType::Events, 700);
- resource_limit->SetLimitValue(ResourceType::TransferMemory, 128);
- resource_limit->SetLimitValue(ResourceType::Sessions, 894);
- ASSERT(resource_limit->Reserve(ResourceType::PhysicalMemory, code_size));
+ resource_limit->SetLimitValue(LimitableResource::Threads, 608);
+ resource_limit->SetLimitValue(LimitableResource::Events, 700);
+ resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
+ resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
// Create TLS region
tls_region_address = CreateTLSRegion();
+ memory_reservation.Commit();
return handle_table.SetSize(capabilities.GetHandleTableSize());
}
void Process::Run(s32 main_thread_priority, u64 stack_size) {
AllocateMainThreadStack(stack_size);
+ resource_limit->Reserve(LimitableResource::Threads, 1);
+ resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size};
ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError());
@@ -302,14 +346,12 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
ChangeStatus(ProcessStatus::Running);
SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top);
- resource_limit->Reserve(ResourceType::Threads, 1);
- resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size);
}
void Process::PrepareForTermination() {
ChangeStatus(ProcessStatus::Exiting);
- const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) {
+ const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) {
for (auto& thread : thread_list) {
if (thread->GetOwnerProcess() != this)
continue;
@@ -318,10 +360,10 @@ void Process::PrepareForTermination() {
continue;
// TODO(Subv): When are the other running/ready threads terminated?
- ASSERT_MSG(thread->GetStatus() == ThreadStatus::WaitSynch,
+ ASSERT_MSG(thread->GetState() == ThreadState::Waiting,
"Exiting processes with non-waiting threads is currently unimplemented");
- thread->Stop();
+ thread->Exit();
}
};
@@ -330,6 +372,11 @@ void Process::PrepareForTermination() {
FreeTLSRegion(tls_region_address);
tls_region_address = 0;
+ if (resource_limit) {
+ resource_limit->Release(LimitableResource::PhysicalMemory,
+ main_thread_stack_size + image_size);
+ }
+
ChangeStatus(ProcessStatus::Exited);
}
@@ -406,21 +453,18 @@ void Process::LoadModule(CodeSet code_set, VAddr base_addr) {
ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite);
}
+bool Process::IsSignaled() const {
+ ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ return is_signaled;
+}
+
Process::Process(Core::System& system)
- : SynchronizationObject{system.Kernel()}, page_table{std::make_unique<Memory::PageTable>(
- system)},
- handle_table{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
+ : KSynchronizationObject{system.Kernel()},
+ page_table{std::make_unique<Memory::PageTable>(system)}, handle_table{system.Kernel()},
+ address_arbiter{system}, condition_var{system}, state_lock{system.Kernel()}, system{system} {}
Process::~Process() = default;
-void Process::Acquire(Thread* thread) {
- ASSERT_MSG(!ShouldWait(thread), "Object unavailable!");
-}
-
-bool Process::ShouldWait(const Thread* thread) const {
- return !is_signaled;
-}
-
void Process::ChangeStatus(ProcessStatus new_status) {
if (status == new_status) {
return;
@@ -428,7 +472,7 @@ void Process::ChangeStatus(ProcessStatus new_status) {
status = new_status;
is_signaled = true;
- Signal();
+ NotifyAvailable();
}
ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) {