low_precision_timer.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "third_party/webrtc_overrides/low_precision_timer.h"
  5. #include "base/check.h"
  6. #include "third_party/webrtc_overrides/task_queue_factory.h"
  7. namespace blink {
  8. LowPrecisionTimer::SchedulableCallback::SchedulableCallback(
  9. scoped_refptr<base::SequencedTaskRunner> task_runner,
  10. base::RepeatingCallback<void()> callback,
  11. base::TimeDelta repeated_delay)
  12. : task_runner_(std::move(task_runner)),
  13. callback_(std::move(callback)),
  14. repeated_delay_(std::move(repeated_delay)) {}
  15. LowPrecisionTimer::SchedulableCallback::~SchedulableCallback() {
  16. DCHECK(!is_active_);
  17. }
  18. void LowPrecisionTimer::SchedulableCallback::Schedule(
  19. base::TimeTicks scheduled_time) {
  20. base::AutoLock auto_scheduled_time_lock(scheduled_time_lock_);
  21. DCHECK_EQ(scheduled_time_, base::TimeTicks::Max())
  22. << "The callback has already been scheduled.";
  23. scheduled_time_ = scheduled_time;
  24. // Snap target time to metronome tick!
  25. base::TimeTicks target_time =
  26. MetronomeSource::TimeSnappedToNextTick(scheduled_time_);
  27. task_runner_->PostDelayedTaskAt(
  28. base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
  29. base::BindOnce(&LowPrecisionTimer::SchedulableCallback::MaybeRun, this),
  30. target_time, base::subtle::DelayPolicy::kPrecise);
  31. }
  32. bool LowPrecisionTimer::SchedulableCallback::IsScheduled() {
  33. base::AutoLock auto_scheduled_time_lock(scheduled_time_lock_);
  34. return scheduled_time_ != base::TimeTicks::Max();
  35. }
  36. base::TimeTicks LowPrecisionTimer::SchedulableCallback::Inactivate() {
  37. // If we're inside the task runner and the task is currently running, that
  38. // means Inactivate() was called from inside the callback, and |active_lock_|
  39. // is already aquired on the current task runner. Acquiring it again would
  40. // cause deadlock.
  41. bool is_inactivated_by_callback =
  42. task_runner_->RunsTasksInCurrentSequence() && is_currently_running_;
  43. std::unique_ptr<base::AutoLock> auto_active_lock;
  44. if (!is_inactivated_by_callback) {
  45. auto_active_lock = std::make_unique<base::AutoLock>(active_lock_);
  46. }
  47. is_active_ = false;
  48. repeated_delay_ = base::TimeDelta(); // Prevent automatic re-schedule.
  49. base::AutoLock auto_scheduled_time_lock(scheduled_time_lock_);
  50. return scheduled_time_;
  51. }
  52. void LowPrecisionTimer::SchedulableCallback::MaybeRun() {
  53. DCHECK(task_runner_->RunsTasksInCurrentSequence());
  54. // Run unless we've been cancelled.
  55. base::AutoLock auto_active_lock(active_lock_);
  56. if (!is_active_) {
  57. return;
  58. }
  59. {
  60. // Reset scheduled time as to allow re-scheduling. Release the lock to allow
  61. // the callback to re-schedule without deadlock.
  62. base::AutoLock auto_scheduled_time_lock(scheduled_time_lock_);
  63. scheduled_time_ = base::TimeTicks::Max();
  64. }
  65. is_currently_running_ = true;
  66. callback_.Run();
  67. is_currently_running_ = false;
  68. if (!repeated_delay_.is_zero()) {
  69. Schedule(base::TimeTicks::Now() + repeated_delay_);
  70. }
  71. }
  72. LowPrecisionTimer::LowPrecisionTimer(
  73. scoped_refptr<base::SequencedTaskRunner> task_runner,
  74. base::RepeatingCallback<void()> callback)
  75. : callback_(std::move(callback)), task_runner_(std::move(task_runner)) {}
  76. LowPrecisionTimer::~LowPrecisionTimer() {
  77. DCHECK(is_shutdown_);
  78. DCHECK(!schedulable_callback_);
  79. }
  80. void LowPrecisionTimer::Shutdown() {
  81. base::AutoLock auto_lock(lock_);
  82. if (is_shutdown_) {
  83. // Already shut down.
  84. return;
  85. }
  86. if (schedulable_callback_) {
  87. schedulable_callback_->Inactivate();
  88. schedulable_callback_ = nullptr;
  89. }
  90. is_shutdown_ = true;
  91. }
  92. void LowPrecisionTimer::StartOneShot(base::TimeDelta delay) {
  93. DCHECK_GE(delay, base::TimeDelta());
  94. base::AutoLock auto_lock(lock_);
  95. DCHECK(!is_shutdown_);
  96. repeated_delay_ = base::TimeDelta(); // Not repeating.
  97. ScheduleCallback(base::TimeTicks::Now() + delay);
  98. }
  99. void LowPrecisionTimer::StartRepeating(base::TimeDelta delay) {
  100. DCHECK_GE(delay, base::TimeDelta());
  101. base::AutoLock auto_lock(lock_);
  102. DCHECK(!is_shutdown_);
  103. repeated_delay_ = delay;
  104. ScheduleCallback(base::TimeTicks::Now() + delay);
  105. }
  106. bool LowPrecisionTimer::IsActive() {
  107. base::AutoLock auto_lock(lock_);
  108. if (!schedulable_callback_) {
  109. return false;
  110. }
  111. if (!repeated_delay_.is_zero()) {
  112. return true;
  113. }
  114. return schedulable_callback_->IsScheduled();
  115. }
  116. void LowPrecisionTimer::Stop() {
  117. base::AutoLock auto_lock(lock_);
  118. if (!schedulable_callback_)
  119. return;
  120. repeated_delay_ = base::TimeDelta(); // Not repeating.
  121. schedulable_callback_->Inactivate();
  122. schedulable_callback_ = nullptr;
  123. }
  124. // EXCLUSIVE_LOCKS_REQUIRED(lock_)
  125. void LowPrecisionTimer::ScheduleCallback(base::TimeTicks scheduled_time) {
  126. if (!schedulable_callback_) {
  127. schedulable_callback_ = base::MakeRefCounted<SchedulableCallback>(
  128. task_runner_, callback_, repeated_delay_);
  129. }
  130. schedulable_callback_->Schedule(scheduled_time);
  131. }
  132. // EXCLUSIVE_LOCKS_REQUIRED(lock_)
  133. void LowPrecisionTimer::RescheduleCallback() {
  134. if (!schedulable_callback_)
  135. return;
  136. base::TimeTicks cancelled_scheduled_time =
  137. schedulable_callback_->Inactivate();
  138. schedulable_callback_ = nullptr;
  139. if (cancelled_scheduled_time == base::TimeTicks::Max())
  140. return; // We don't have a scheduled time.
  141. ScheduleCallback(cancelled_scheduled_time);
  142. }
  143. void LowPrecisionTimer::MoveToNewTaskRunner(
  144. scoped_refptr<base::SequencedTaskRunner> task_runner) {
  145. base::AutoLock auto_lock(lock_);
  146. DCHECK(task_runner);
  147. task_runner_ = std::move(task_runner);
  148. RescheduleCallback();
  149. }
  150. } // namespace blink