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:
		| @@ -202,6 +202,16 @@ public: | ||||
|         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 | ||||
|      * by an executable. | ||||
| @@ -305,6 +315,9 @@ private: | ||||
|     /// specified by metadata provided to the process during loading. | ||||
|     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. | ||||
|     HandleTable handle_table; | ||||
|  | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "common/logging/log.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/scheduler.h" | ||||
| @@ -34,6 +35,10 @@ Thread* Scheduler::GetCurrentThread() const { | ||||
|     return current_thread.get(); | ||||
| } | ||||
|  | ||||
| u64 Scheduler::GetLastContextSwitchTicks() const { | ||||
|     return last_context_switch_time; | ||||
| } | ||||
|  | ||||
| Thread* Scheduler::PopNextReadyThread() { | ||||
|     Thread* next = nullptr; | ||||
|     Thread* thread = GetCurrentThread(); | ||||
| @@ -54,7 +59,10 @@ Thread* Scheduler::PopNextReadyThread() { | ||||
| } | ||||
|  | ||||
| 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 | ||||
|     if (previous_thread) { | ||||
| @@ -78,8 +86,6 @@ void Scheduler::SwitchContext(Thread* new_thread) { | ||||
|         // Cancel any outstanding wakeup events for this thread | ||||
|         new_thread->CancelWakeupTimer(); | ||||
|  | ||||
|         auto* const previous_process = Core::CurrentProcess(); | ||||
|  | ||||
|         current_thread = 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() { | ||||
|     std::lock_guard<std::mutex> lock(scheduler_mutex); | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,8 @@ class ARM_Interface; | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class Process; | ||||
|  | ||||
| class Scheduler final { | ||||
| public: | ||||
|     explicit Scheduler(Core::ARM_Interface& cpu_core); | ||||
| @@ -31,6 +33,9 @@ public: | ||||
|     /// Gets the current running thread | ||||
|     Thread* GetCurrentThread() const; | ||||
|  | ||||
|     /// Gets the timestamp for the last context switch in ticks. | ||||
|     u64 GetLastContextSwitchTicks() const; | ||||
|  | ||||
|     /// Adds a new thread to the scheduler | ||||
|     void AddThread(SharedPtr<Thread> thread, u32 priority); | ||||
|  | ||||
| @@ -64,6 +69,19 @@ private: | ||||
|      */ | ||||
|     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. | ||||
|     std::vector<SharedPtr<Thread>> thread_list; | ||||
|  | ||||
| @@ -73,6 +91,7 @@ private: | ||||
|     SharedPtr<Thread> current_thread = nullptr; | ||||
|  | ||||
|     Core::ARM_Interface& cpu_core; | ||||
|     u64 last_context_switch_time = 0; | ||||
|  | ||||
|     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"); | ||||
|         *result = 0; | ||||
|         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: | ||||
|         UNIMPLEMENTED(); | ||||
|     } | ||||
|   | ||||
| @@ -53,6 +53,7 @@ enum class GetInfoType : u64 { | ||||
|     PrivilegedProcessId = 19, | ||||
|     // 5.0.0+ | ||||
|     UserExceptionContextAddr = 20, | ||||
|     ThreadTickCount = 0xF0000002, | ||||
| }; | ||||
|  | ||||
| void CallSVC(u32 immediate); | ||||
|   | ||||
| @@ -258,6 +258,14 @@ public: | ||||
|         return last_running_ticks; | ||||
|     } | ||||
|  | ||||
|     u64 GetTotalCPUTimeTicks() const { | ||||
|         return total_cpu_time_ticks; | ||||
|     } | ||||
|  | ||||
|     void UpdateCPUTimeTicks(u64 ticks) { | ||||
|         total_cpu_time_ticks += ticks; | ||||
|     } | ||||
|  | ||||
|     s32 GetProcessorID() const { | ||||
|         return processor_id; | ||||
|     } | ||||
| @@ -378,7 +386,8 @@ private: | ||||
|     u32 nominal_priority = 0; ///< Nominal thread priority, as set by the emulated application | ||||
|     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; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Lioncash
					Lioncash