ThreadTimers.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*
  2. * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
  3. * Copyright (C) 2009 Google Inc. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  18. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  21. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "config.h"
  27. #include "ThreadTimers.h"
  28. #include "SharedTimer.h"
  29. #include "ThreadGlobalData.h"
  30. #include "Timer.h"
  31. #include <wtf/CurrentTime.h>
  32. #include <wtf/MainThread.h>
  33. using namespace std;
  34. namespace WebCore {
  35. // Fire timers for this length of time, and then quit to let the run loop process user input events.
  36. // 100ms is about a perceptable delay in UI, so use a half of that as a threshold.
  37. // This is to prevent UI freeze when there are too many timers or machine performance is low.
  38. static const double maxDurationOfFiringTimers = 0.050;
  39. // Timers are created, started and fired on the same thread, and each thread has its own ThreadTimers
  40. // copy to keep the heap and a set of currently firing timers.
  41. static MainThreadSharedTimer* mainThreadSharedTimer()
  42. {
  43. static MainThreadSharedTimer* timer = new MainThreadSharedTimer;
  44. return timer;
  45. }
  46. ThreadTimers::ThreadTimers()
  47. : m_sharedTimer(0)
  48. , m_firingTimers(false)
  49. , m_pendingSharedTimerFireTime(0)
  50. {
  51. if (isMainThread())
  52. setSharedTimer(mainThreadSharedTimer());
  53. }
  54. // A worker thread may initialize SharedTimer after some timers are created.
  55. // Also, SharedTimer can be replaced with 0 before all timers are destroyed.
  56. void ThreadTimers::setSharedTimer(SharedTimer* sharedTimer)
  57. {
  58. if (m_sharedTimer) {
  59. m_sharedTimer->setFiredFunction(0);
  60. m_sharedTimer->stop();
  61. m_pendingSharedTimerFireTime = 0;
  62. }
  63. m_sharedTimer = sharedTimer;
  64. if (sharedTimer) {
  65. m_sharedTimer->setFiredFunction(ThreadTimers::sharedTimerFired);
  66. updateSharedTimer();
  67. }
  68. }
  69. void ThreadTimers::updateSharedTimer()
  70. {
  71. if (!m_sharedTimer)
  72. return;
  73. if (m_firingTimers || m_timerHeap.isEmpty()) {
  74. m_pendingSharedTimerFireTime = 0;
  75. m_sharedTimer->stop();
  76. } else {
  77. double nextFireTime = m_timerHeap.first()->m_nextFireTime;
  78. double currentMonotonicTime = monotonicallyIncreasingTime();
  79. if (m_pendingSharedTimerFireTime) {
  80. // No need to restart the timer if both the pending fire time and the new fire time are in the past.
  81. if (m_pendingSharedTimerFireTime <= currentMonotonicTime && nextFireTime <= currentMonotonicTime)
  82. return;
  83. }
  84. m_pendingSharedTimerFireTime = nextFireTime;
  85. m_sharedTimer->setFireInterval(max(nextFireTime - currentMonotonicTime, 0.0));
  86. }
  87. }
  88. void ThreadTimers::sharedTimerFired()
  89. {
  90. // Redirect to non-static method.
  91. threadGlobalData().threadTimers().sharedTimerFiredInternal();
  92. }
  93. void ThreadTimers::sharedTimerFiredInternal()
  94. {
  95. // Do a re-entrancy check.
  96. if (m_firingTimers)
  97. return;
  98. m_firingTimers = true;
  99. m_pendingSharedTimerFireTime = 0;
  100. double fireTime = monotonicallyIncreasingTime();
  101. double timeToQuit = fireTime + maxDurationOfFiringTimers;
  102. while (!m_timerHeap.isEmpty() && m_timerHeap.first()->m_nextFireTime <= fireTime) {
  103. TimerBase* timer = m_timerHeap.first();
  104. timer->m_nextFireTime = 0;
  105. timer->m_unalignedNextFireTime = 0;
  106. timer->heapDeleteMin();
  107. double interval = timer->repeatInterval();
  108. timer->setNextFireTime(interval ? fireTime + interval : 0);
  109. // Once the timer has been fired, it may be deleted, so do nothing else with it after this point.
  110. timer->fired();
  111. // Catch the case where the timer asked timers to fire in a nested event loop, or we are over time limit.
  112. if (!m_firingTimers || timeToQuit < monotonicallyIncreasingTime())
  113. break;
  114. }
  115. m_firingTimers = false;
  116. updateSharedTimer();
  117. }
  118. void ThreadTimers::fireTimersInNestedEventLoop()
  119. {
  120. // Reset the reentrancy guard so the timers can fire again.
  121. m_firingTimers = false;
  122. updateSharedTimer();
  123. }
  124. } // namespace WebCore