kernel/svc: Implement svcGetThreadList
Similarly like svcGetProcessList, this retrieves the list of threads from the current process. In the kernel itself, a process instance maintains a list of threads, which are used within this function. Threads are registered to a process' thread list at thread initialization, and unregistered from the list upon thread destruction (if said thread has a non-null owning process). We assert on the debug event case, as we currently don't implement kernel debug objects.
This commit is contained in:
parent
cb2bce8006
commit
28719ee3b4
@ -80,6 +80,14 @@ u64 Process::GetTotalPhysicalMemoryUsed() const {
|
|||||||
return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size;
|
return vm_manager.GetCurrentHeapSize() + main_thread_stack_size + code_memory_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Process::RegisterThread(const Thread* thread) {
|
||||||
|
thread_list.push_back(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::UnregisterThread(const Thread* thread) {
|
||||||
|
thread_list.remove(thread);
|
||||||
|
}
|
||||||
|
|
||||||
ResultCode Process::ClearSignalState() {
|
ResultCode Process::ClearSignalState() {
|
||||||
if (status == ProcessStatus::Exited) {
|
if (status == ProcessStatus::Exited) {
|
||||||
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
LOG_ERROR(Kernel, "called on a terminated process instance.");
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/container/static_vector.hpp>
|
#include <boost/container/static_vector.hpp>
|
||||||
@ -189,6 +190,19 @@ public:
|
|||||||
/// Retrieves the total physical memory used by this process in bytes.
|
/// Retrieves the total physical memory used by this process in bytes.
|
||||||
u64 GetTotalPhysicalMemoryUsed() const;
|
u64 GetTotalPhysicalMemoryUsed() const;
|
||||||
|
|
||||||
|
/// Gets the list of all threads created with this process as their owner.
|
||||||
|
const std::list<const Thread*>& GetThreadList() const {
|
||||||
|
return thread_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers a thread as being created under this process,
|
||||||
|
/// adding it to this process' thread list.
|
||||||
|
void RegisterThread(const Thread* thread);
|
||||||
|
|
||||||
|
/// Unregisters a thread from this process, removing it
|
||||||
|
/// from this process' thread list.
|
||||||
|
void UnregisterThread(const Thread* thread);
|
||||||
|
|
||||||
/// Clears the signaled state of the process if and only if it's signaled.
|
/// Clears the signaled state of the process if and only if it's signaled.
|
||||||
///
|
///
|
||||||
/// @pre The process must not be already terminated. If this is called on a
|
/// @pre The process must not be already terminated. If this is called on a
|
||||||
@ -308,6 +322,9 @@ private:
|
|||||||
/// Random values for svcGetInfo RandomEntropy
|
/// Random values for svcGetInfo RandomEntropy
|
||||||
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
|
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
|
||||||
|
|
||||||
|
/// List of threads that are running with this process as their owner.
|
||||||
|
std::list<const Thread*> thread_list;
|
||||||
|
|
||||||
/// System context
|
/// System context
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
@ -2020,6 +2020,46 @@ static ResultCode GetProcessList(u32* out_num_processes, VAddr out_process_ids,
|
|||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultCode GetThreadList(u32* out_num_threads, VAddr out_thread_ids, u32 out_thread_ids_size,
|
||||||
|
Handle debug_handle) {
|
||||||
|
// TODO: Handle this case when debug events are supported.
|
||||||
|
UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
|
||||||
|
|
||||||
|
LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}",
|
||||||
|
out_thread_ids, out_thread_ids_size);
|
||||||
|
|
||||||
|
// If the size is negative or larger than INT32_MAX / sizeof(u64)
|
||||||
|
if ((out_thread_ids_size & 0xF0000000) != 0) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
|
||||||
|
out_thread_ids_size);
|
||||||
|
return ERR_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
|
||||||
|
const auto& vm_manager = current_process->VMManager();
|
||||||
|
const auto total_copy_size = out_thread_ids_size * sizeof(u64);
|
||||||
|
|
||||||
|
if (out_thread_ids_size > 0 &&
|
||||||
|
!vm_manager.IsWithinAddressSpace(out_thread_ids, total_copy_size)) {
|
||||||
|
LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
|
||||||
|
out_thread_ids, out_thread_ids + total_copy_size);
|
||||||
|
return ERR_INVALID_ADDRESS_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& thread_list = current_process->GetThreadList();
|
||||||
|
const auto num_threads = thread_list.size();
|
||||||
|
const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
|
||||||
|
|
||||||
|
auto list_iter = thread_list.cbegin();
|
||||||
|
for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
|
||||||
|
Memory::Write64(out_thread_ids, (*list_iter)->GetThreadID());
|
||||||
|
out_thread_ids += sizeof(u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_num_threads = static_cast<u32>(num_threads);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct FunctionDef {
|
struct FunctionDef {
|
||||||
using Func = void();
|
using Func = void();
|
||||||
@ -2133,7 +2173,7 @@ static const FunctionDef SVC_Table[] = {
|
|||||||
{0x63, nullptr, "GetDebugEvent"},
|
{0x63, nullptr, "GetDebugEvent"},
|
||||||
{0x64, nullptr, "ContinueDebugEvent"},
|
{0x64, nullptr, "ContinueDebugEvent"},
|
||||||
{0x65, SvcWrap<GetProcessList>, "GetProcessList"},
|
{0x65, SvcWrap<GetProcessList>, "GetProcessList"},
|
||||||
{0x66, nullptr, "GetThreadList"},
|
{0x66, SvcWrap<GetThreadList>, "GetThreadList"},
|
||||||
{0x67, nullptr, "GetDebugThreadContext"},
|
{0x67, nullptr, "GetDebugThreadContext"},
|
||||||
{0x68, nullptr, "SetDebugThreadContext"},
|
{0x68, nullptr, "SetDebugThreadContext"},
|
||||||
{0x69, nullptr, "QueryDebugProcessMemory"},
|
{0x69, nullptr, "QueryDebugProcessMemory"},
|
||||||
|
@ -62,6 +62,8 @@ void Thread::Stop() {
|
|||||||
}
|
}
|
||||||
wait_objects.clear();
|
wait_objects.clear();
|
||||||
|
|
||||||
|
owner_process->UnregisterThread(this);
|
||||||
|
|
||||||
// Mark the TLS slot in the thread's page as free.
|
// Mark the TLS slot in the thread's page as free.
|
||||||
owner_process->FreeTLSSlot(tls_address);
|
owner_process->FreeTLSSlot(tls_address);
|
||||||
}
|
}
|
||||||
@ -202,6 +204,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
|
|||||||
thread->scheduler->AddThread(thread);
|
thread->scheduler->AddThread(thread);
|
||||||
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
|
thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
|
||||||
|
|
||||||
|
thread->owner_process->RegisterThread(thread.get());
|
||||||
|
|
||||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||||
// to initialize the context
|
// to initialize the context
|
||||||
ResetThreadContext(thread->context, stack_top, entry_point, arg);
|
ResetThreadContext(thread->context, stack_top, entry_point, arg);
|
||||||
|
Loading…
Reference in New Issue
Block a user