svc: Implement svcGetInfo command 0xF0000002
This retrieves: if (curr_thread == handle_thread) { result = total_thread_ticks + (hardware_tick_count - last_context_switch_ticks); } else if (curr_thread == handle_thread && sub_id == current_core_index) { result = hardware_tick_count - last_context_switch_ticks; }
This commit is contained in:
parent
d278f25bda
commit
6594853eb1
|
@ -202,6 +202,16 @@ public:
|
||||||
return is_64bit_process;
|
return is_64bit_process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the total running time of the process instance in ticks.
|
||||||
|
u64 GetCPUTimeTicks() const {
|
||||||
|
return total_process_running_time_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the total running time, adding the given ticks to it.
|
||||||
|
void UpdateCPUTimeTicks(u64 ticks) {
|
||||||
|
total_process_running_time_ticks += ticks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads process-specifics configuration info with metadata provided
|
* Loads process-specifics configuration info with metadata provided
|
||||||
* by an executable.
|
* by an executable.
|
||||||
|
@ -305,6 +315,9 @@ private:
|
||||||
/// specified by metadata provided to the process during loading.
|
/// specified by metadata provided to the process during loading.
|
||||||
bool is_64bit_process = true;
|
bool is_64bit_process = true;
|
||||||
|
|
||||||
|
/// Total running time for the process in ticks.
|
||||||
|
u64 total_process_running_time_ticks = 0;
|
||||||
|
|
||||||
/// Per-process handle table for storing created object handles in.
|
/// Per-process handle table for storing created object handles in.
|
||||||
HandleTable handle_table;
|
HandleTable handle_table;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/scheduler.h"
|
#include "core/hle/kernel/scheduler.h"
|
||||||
|
@ -34,6 +35,10 @@ Thread* Scheduler::GetCurrentThread() const {
|
||||||
return current_thread.get();
|
return current_thread.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 Scheduler::GetLastContextSwitchTicks() const {
|
||||||
|
return last_context_switch_time;
|
||||||
|
}
|
||||||
|
|
||||||
Thread* Scheduler::PopNextReadyThread() {
|
Thread* Scheduler::PopNextReadyThread() {
|
||||||
Thread* next = nullptr;
|
Thread* next = nullptr;
|
||||||
Thread* thread = GetCurrentThread();
|
Thread* thread = GetCurrentThread();
|
||||||
|
@ -54,7 +59,10 @@ Thread* Scheduler::PopNextReadyThread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::SwitchContext(Thread* new_thread) {
|
void Scheduler::SwitchContext(Thread* new_thread) {
|
||||||
Thread* previous_thread = GetCurrentThread();
|
Thread* const previous_thread = GetCurrentThread();
|
||||||
|
Process* const previous_process = Core::CurrentProcess();
|
||||||
|
|
||||||
|
UpdateLastContextSwitchTime(previous_thread, previous_process);
|
||||||
|
|
||||||
// Save context for previous thread
|
// Save context for previous thread
|
||||||
if (previous_thread) {
|
if (previous_thread) {
|
||||||
|
@ -78,8 +86,6 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
new_thread->CancelWakeupTimer();
|
new_thread->CancelWakeupTimer();
|
||||||
|
|
||||||
auto* const previous_process = Core::CurrentProcess();
|
|
||||||
|
|
||||||
current_thread = new_thread;
|
current_thread = new_thread;
|
||||||
|
|
||||||
ready_queue.remove(new_thread->GetPriority(), new_thread);
|
ready_queue.remove(new_thread->GetPriority(), new_thread);
|
||||||
|
@ -102,6 +108,22 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
|
||||||
|
const u64 prev_switch_ticks = last_context_switch_time;
|
||||||
|
const u64 most_recent_switch_ticks = CoreTiming::GetTicks();
|
||||||
|
const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
|
||||||
|
|
||||||
|
if (thread != nullptr) {
|
||||||
|
thread->UpdateCPUTimeTicks(update_ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process != nullptr) {
|
||||||
|
process->UpdateCPUTimeTicks(update_ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_context_switch_time = most_recent_switch_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::Reschedule() {
|
void Scheduler::Reschedule() {
|
||||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ class ARM_Interface;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
|
||||||
class Scheduler final {
|
class Scheduler final {
|
||||||
public:
|
public:
|
||||||
explicit Scheduler(Core::ARM_Interface& cpu_core);
|
explicit Scheduler(Core::ARM_Interface& cpu_core);
|
||||||
|
@ -31,6 +33,9 @@ public:
|
||||||
/// Gets the current running thread
|
/// Gets the current running thread
|
||||||
Thread* GetCurrentThread() const;
|
Thread* GetCurrentThread() const;
|
||||||
|
|
||||||
|
/// Gets the timestamp for the last context switch in ticks.
|
||||||
|
u64 GetLastContextSwitchTicks() const;
|
||||||
|
|
||||||
/// Adds a new thread to the scheduler
|
/// Adds a new thread to the scheduler
|
||||||
void AddThread(SharedPtr<Thread> thread, u32 priority);
|
void AddThread(SharedPtr<Thread> thread, u32 priority);
|
||||||
|
|
||||||
|
@ -64,6 +69,19 @@ private:
|
||||||
*/
|
*/
|
||||||
void SwitchContext(Thread* new_thread);
|
void SwitchContext(Thread* new_thread);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on every context switch to update the internal timestamp
|
||||||
|
* This also updates the running time ticks for the given thread and
|
||||||
|
* process using the following difference:
|
||||||
|
*
|
||||||
|
* ticks += most_recent_ticks - last_context_switch_ticks
|
||||||
|
*
|
||||||
|
* The internal tick timestamp for the scheduler is simply the
|
||||||
|
* most recent tick count retrieved. No special arithmetic is
|
||||||
|
* applied to it.
|
||||||
|
*/
|
||||||
|
void UpdateLastContextSwitchTime(Thread* thread, Process* process);
|
||||||
|
|
||||||
/// Lists all thread ids that aren't deleted/etc.
|
/// Lists all thread ids that aren't deleted/etc.
|
||||||
std::vector<SharedPtr<Thread>> thread_list;
|
std::vector<SharedPtr<Thread>> thread_list;
|
||||||
|
|
||||||
|
@ -73,6 +91,7 @@ private:
|
||||||
SharedPtr<Thread> current_thread = nullptr;
|
SharedPtr<Thread> current_thread = nullptr;
|
||||||
|
|
||||||
Core::ARM_Interface& cpu_core;
|
Core::ARM_Interface& cpu_core;
|
||||||
|
u64 last_context_switch_time = 0;
|
||||||
|
|
||||||
static std::mutex scheduler_mutex;
|
static std::mutex scheduler_mutex;
|
||||||
};
|
};
|
||||||
|
|
|
@ -529,6 +529,36 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||||
"(STUBBED) Attempted to query user exception context address, returned 0");
|
"(STUBBED) Attempted to query user exception context address, returned 0");
|
||||||
*result = 0;
|
*result = 0;
|
||||||
break;
|
break;
|
||||||
|
case GetInfoType::ThreadTickCount: {
|
||||||
|
constexpr u64 num_cpus = 4;
|
||||||
|
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
|
||||||
|
return ERR_INVALID_COMBINATION_KERNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto thread =
|
||||||
|
current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
|
||||||
|
if (!thread) {
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
const auto& scheduler = system.CurrentScheduler();
|
||||||
|
const auto* const current_thread = scheduler.GetCurrentThread();
|
||||||
|
const bool same_thread = current_thread == thread;
|
||||||
|
|
||||||
|
const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
|
||||||
|
u64 out_ticks = 0;
|
||||||
|
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
|
||||||
|
const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
|
||||||
|
|
||||||
|
out_ticks = thread_ticks + (CoreTiming::GetTicks() - prev_ctx_ticks);
|
||||||
|
} else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
|
||||||
|
out_ticks = CoreTiming::GetTicks() - prev_ctx_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = out_ticks;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ enum class GetInfoType : u64 {
|
||||||
PrivilegedProcessId = 19,
|
PrivilegedProcessId = 19,
|
||||||
// 5.0.0+
|
// 5.0.0+
|
||||||
UserExceptionContextAddr = 20,
|
UserExceptionContextAddr = 20,
|
||||||
|
ThreadTickCount = 0xF0000002,
|
||||||
};
|
};
|
||||||
|
|
||||||
void CallSVC(u32 immediate);
|
void CallSVC(u32 immediate);
|
||||||
|
|
|
@ -258,6 +258,14 @@ public:
|
||||||
return last_running_ticks;
|
return last_running_ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 GetTotalCPUTimeTicks() const {
|
||||||
|
return total_cpu_time_ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCPUTimeTicks(u64 ticks) {
|
||||||
|
total_cpu_time_ticks += ticks;
|
||||||
|
}
|
||||||
|
|
||||||
s32 GetProcessorID() const {
|
s32 GetProcessorID() const {
|
||||||
return processor_id;
|
return processor_id;
|
||||||
}
|
}
|
||||||
|
@ -378,7 +386,8 @@ private:
|
||||||
u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application
|
u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application
|
||||||
u32 current_priority = 0; ///< Current thread priority, can be temporarily changed
|
u32 current_priority = 0; ///< Current thread priority, can be temporarily changed
|
||||||
|
|
||||||
u64 last_running_ticks = 0; ///< CPU tick when thread was last running
|
u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks.
|
||||||
|
u64 last_running_ticks = 0; ///< CPU tick when thread was last running
|
||||||
|
|
||||||
s32 processor_id = 0;
|
s32 processor_id = 0;
|
||||||
|
|
||||||
|
|
Reference in New Issue