timer.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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. if (reset_type == ResetType::Pulse) {
  28. LOG_ERROR(Kernel, "Unimplemented timer reset type Pulse");
  29. UNIMPLEMENTED();
  30. }
  31. return timer;
  32. }
  33. bool Timer::ShouldWait() {
  34. return !signaled;
  35. }
  36. void Timer::Acquire() {
  37. ASSERT_MSG(!ShouldWait(), "object unavailable!");
  38. if (reset_type == ResetType::OneShot)
  39. signaled = false;
  40. }
  41. void Timer::Set(s64 initial, s64 interval) {
  42. // Ensure we get rid of any previous scheduled event
  43. Cancel();
  44. initial_delay = initial;
  45. interval_delay = interval;
  46. u64 initial_microseconds = initial / 1000;
  47. CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
  48. callback_handle);
  49. HLE::Reschedule(__func__);
  50. }
  51. void Timer::Cancel() {
  52. CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
  53. HLE::Reschedule(__func__);
  54. }
  55. void Timer::Clear() {
  56. signaled = false;
  57. }
  58. /// The timer callback event, called when a timer is fired
  59. static void TimerCallback(u64 timer_handle, int cycles_late) {
  60. SharedPtr<Timer> timer =
  61. timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
  62. if (timer == nullptr) {
  63. LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle);
  64. return;
  65. }
  66. LOG_TRACE(Kernel, "Timer %08" PRIx64 " fired", timer_handle);
  67. timer->signaled = true;
  68. // Resume all waiting threads
  69. timer->WakeupAllWaitingThreads();
  70. if (timer->interval_delay != 0) {
  71. // Reschedule the timer with the interval delay
  72. u64 interval_microseconds = timer->interval_delay / 1000;
  73. CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
  74. timer_callback_event_type, timer_handle);
  75. }
  76. }
  77. void TimersInit() {
  78. timer_callback_handle_table.Clear();
  79. timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
  80. }
  81. void TimersShutdown() {}
  82. } // namespace