timer.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Copyright 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cinttypes>
  5. #include "common/assert.h"
  6. #include "common/logging/log.h"
  7. #include "core/core_timing.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/timer.h"
  10. #include "core/hle/kernel/thread.h"
  11. namespace Kernel {
  12. /// The event type of the generic timer callback event
  13. static int timer_callback_event_type;
  14. // TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
  15. // us to simply use a pool index or similar.
  16. static Kernel::HandleTable timer_callback_handle_table;
  17. Timer::Timer() {}
  18. Timer::~Timer() {}
  19. SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
  20. SharedPtr<Timer> timer(new Timer);
  21. timer->reset_type = reset_type;
  22. timer->signaled = false;
  23. timer->name = std::move(name);
  24. timer->initial_delay = 0;
  25. timer->interval_delay = 0;
  26. timer->callback_handle = timer_callback_handle_table.Create(timer).MoveFrom();
  27. return timer;
  28. }
  29. bool Timer::ShouldWait() {
  30. return !signaled;
  31. }
  32. void Timer::Acquire() {
  33. ASSERT_MSG( !ShouldWait(), "object unavailable!");
  34. if (reset_type == RESETTYPE_ONESHOT)
  35. signaled = false;
  36. }
  37. void Timer::Set(s64 initial, s64 interval) {
  38. // Ensure we get rid of any previous scheduled event
  39. Cancel();
  40. initial_delay = initial;
  41. interval_delay = interval;
  42. u64 initial_microseconds = initial / 1000;
  43. CoreTiming::ScheduleEvent(usToCycles(initial_microseconds),
  44. timer_callback_event_type, callback_handle);
  45. HLE::Reschedule(__func__);
  46. }
  47. void Timer::Cancel() {
  48. CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
  49. HLE::Reschedule(__func__);
  50. }
  51. void Timer::Clear() {
  52. signaled = false;
  53. }
  54. /// The timer callback event, called when a timer is fired
  55. static void TimerCallback(u64 timer_handle, int cycles_late) {
  56. SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
  57. if (timer == nullptr) {
  58. LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle);
  59. return;
  60. }
  61. LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle);
  62. timer->signaled = true;
  63. // Resume all waiting threads
  64. timer->WakeupAllWaitingThreads();
  65. if (timer->interval_delay != 0) {
  66. // Reschedule the timer with the interval delay
  67. u64 interval_microseconds = timer->interval_delay / 1000;
  68. CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
  69. timer_callback_event_type, timer_handle);
  70. }
  71. }
  72. void TimersInit() {
  73. timer_callback_handle_table.Clear();
  74. timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
  75. }
  76. void TimersShutdown() {
  77. }
  78. } // namespace