timer.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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/thread.h"
  10. #include "core/hle/kernel/timer.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(Thread* thread) const {
  30. return !signaled;
  31. }
  32. void Timer::Acquire(Thread* thread) {
  33. ASSERT_MSG(!ShouldWait(thread), "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. if (initial == 0) {
  43. // Immediately invoke the callback
  44. Signal(0);
  45. } else {
  46. u64 initial_microseconds = initial / 1000;
  47. CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
  48. callback_handle);
  49. }
  50. }
  51. void Timer::Cancel() {
  52. CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
  53. }
  54. void Timer::Clear() {
  55. signaled = false;
  56. }
  57. void Timer::WakeupAllWaitingThreads() {
  58. WaitObject::WakeupAllWaitingThreads();
  59. if (reset_type == ResetType::Pulse)
  60. signaled = false;
  61. }
  62. void Timer::Signal(int cycles_late) {
  63. LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle);
  64. // Resume all waiting threads
  65. WakeupAllWaitingThreads();
  66. if (interval_delay != 0) {
  67. // Reschedule the timer with the interval delay
  68. u64 interval_microseconds = interval_delay / 1000;
  69. CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
  70. timer_callback_event_type, callback_handle);
  71. }
  72. }
  73. /// The timer callback event, called when a timer is fired
  74. static void TimerCallback(u64 timer_handle, int cycles_late) {
  75. SharedPtr<Timer> timer =
  76. timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
  77. if (timer == nullptr) {
  78. LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle);
  79. return;
  80. }
  81. timer->Signal(cycles_late);
  82. }
  83. void TimersInit() {
  84. timer_callback_handle_table.Clear();
  85. timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
  86. }
  87. void TimersShutdown() {}
  88. } // namespace