alarms.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/core.h"
  4. #include "core/hle/service/psc/time/alarms.h"
  5. #include "core/hle/service/psc/time/manager.h"
  6. namespace Service::PSC::Time {
  7. Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type)
  8. : m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} {
  9. m_event->Clear();
  10. switch (type) {
  11. case WakeupAlarm:
  12. m_priority = 1;
  13. break;
  14. case BackgroundTaskAlarm:
  15. m_priority = 0;
  16. break;
  17. default:
  18. UNREACHABLE();
  19. return;
  20. }
  21. }
  22. Alarm::~Alarm() {
  23. m_ctx.CloseEvent(m_event);
  24. }
  25. Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock,
  26. PowerStateRequestManager& power_state_request_manager)
  27. : m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock},
  28. m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent(
  29. "Psc:Alarms:Event")} {}
  30. Alarms::~Alarms() {
  31. m_ctx.CloseEvent(m_event);
  32. }
  33. Result Alarms::Enable(Alarm& alarm, s64 time) {
  34. R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized);
  35. std::scoped_lock l{m_mutex};
  36. R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered);
  37. auto time_ns{time + m_steady_clock.GetRawTime()};
  38. auto one_second_ns{
  39. std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
  40. time_ns = Common::AlignUp(time_ns, one_second_ns);
  41. alarm.SetAlertTime(time_ns);
  42. Insert(alarm);
  43. R_RETURN(UpdateClosestAndSignal());
  44. }
  45. void Alarms::Disable(Alarm& alarm) {
  46. std::scoped_lock l{m_mutex};
  47. if (!alarm.IsLinked()) {
  48. return;
  49. }
  50. Erase(alarm);
  51. UpdateClosestAndSignal();
  52. }
  53. void Alarms::CheckAndSignal() {
  54. std::scoped_lock l{m_mutex};
  55. if (m_alarms.empty()) {
  56. return;
  57. }
  58. bool alarm_signalled{false};
  59. for (auto& alarm : m_alarms) {
  60. if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) {
  61. alarm.Signal();
  62. alarm.Lock();
  63. Erase(alarm);
  64. m_power_state_request_manager.UpdatePendingPowerStateRequestPriority(
  65. alarm.GetPriority());
  66. alarm_signalled = true;
  67. }
  68. }
  69. if (!alarm_signalled) {
  70. return;
  71. }
  72. m_power_state_request_manager.SignalPowerStateRequestAvailability();
  73. UpdateClosestAndSignal();
  74. }
  75. bool Alarms::GetClosestAlarm(Alarm** out_alarm) {
  76. std::scoped_lock l{m_mutex};
  77. auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
  78. *out_alarm = alarm;
  79. return alarm != nullptr;
  80. }
  81. void Alarms::Insert(Alarm& alarm) {
  82. // Alarms are sorted by alert time, then priority
  83. auto it{m_alarms.begin()};
  84. while (it != m_alarms.end()) {
  85. if (alarm.GetAlertTime() < it->GetAlertTime() ||
  86. (alarm.GetAlertTime() == it->GetAlertTime() &&
  87. alarm.GetPriority() < it->GetPriority())) {
  88. m_alarms.insert(it, alarm);
  89. return;
  90. }
  91. it++;
  92. }
  93. m_alarms.push_back(alarm);
  94. }
  95. void Alarms::Erase(Alarm& alarm) {
  96. m_alarms.erase(m_alarms.iterator_to(alarm));
  97. }
  98. Result Alarms::UpdateClosestAndSignal() {
  99. m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front());
  100. R_SUCCEED_IF(m_closest_alarm == nullptr);
  101. m_event->Signal();
  102. R_SUCCEED();
  103. }
  104. IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager)
  105. : ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} {
  106. // clang-format off
  107. static const FunctionInfo functions[] = {
  108. {0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"},
  109. {1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"},
  110. };
  111. // clang-format on
  112. RegisterHandlers(functions);
  113. }
  114. void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) {
  115. LOG_DEBUG(Service_Time, "called.");
  116. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  117. rb.Push(ResultSuccess);
  118. rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm);
  119. }
  120. void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) {
  121. LOG_DEBUG(Service_Time, "called.");
  122. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  123. rb.Push(ResultSuccess);
  124. rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm);
  125. }
  126. ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type)
  127. : ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"},
  128. m_alarms{alarms}, m_alarm{system, m_ctx, type} {
  129. // clang-format off
  130. static const FunctionInfo functions[] = {
  131. {0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"},
  132. {1, &ISteadyClockAlarm::Enable, "Enable"},
  133. {2, &ISteadyClockAlarm::Disable, "Disable"},
  134. {3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"},
  135. {10, nullptr, "CreateWakeLock"},
  136. {11, nullptr, "DestroyWakeLock"},
  137. };
  138. // clang-format on
  139. RegisterHandlers(functions);
  140. }
  141. void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) {
  142. LOG_DEBUG(Service_Time, "called.");
  143. IPC::ResponseBuilder rb{ctx, 2, 1};
  144. rb.Push(ResultSuccess);
  145. rb.PushCopyObjects(m_alarm.GetEventHandle());
  146. }
  147. void ISteadyClockAlarm::Enable(HLERequestContext& ctx) {
  148. LOG_DEBUG(Service_Time, "called.");
  149. IPC::RequestParser rp{ctx};
  150. auto time{rp.Pop<s64>()};
  151. auto res = m_alarms.Enable(m_alarm, time);
  152. IPC::ResponseBuilder rb{ctx, 2};
  153. rb.Push(res);
  154. }
  155. void ISteadyClockAlarm::Disable(HLERequestContext& ctx) {
  156. LOG_DEBUG(Service_Time, "called.");
  157. m_alarms.Disable(m_alarm);
  158. IPC::ResponseBuilder rb{ctx, 2};
  159. rb.Push(ResultSuccess);
  160. }
  161. void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) {
  162. LOG_DEBUG(Service_Time, "called.");
  163. IPC::ResponseBuilder rb{ctx, 3};
  164. rb.Push(ResultSuccess);
  165. rb.Push<bool>(m_alarm.IsLinked());
  166. }
  167. } // namespace Service::PSC::Time