timer.cpp 2.8 KB

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