OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. |
3 * Copyright (C) 2009 Google Inc. All rights reserved. | 3 * Copyright (C) 2009 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
11 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
12 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
13 * | 13 * |
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 */ | 25 */ |
26 | 26 |
27 #include "config.h" | 27 #include "config.h" |
28 #include "platform/Timer.h" | 28 #include "platform/Timer.h" |
29 | 29 |
30 #include "platform/TraceEvent.h" | 30 #include "platform/PlatformThreadData.h" |
31 #include "public/platform/Platform.h" | 31 #include "platform/ThreadTimers.h" |
32 #include "wtf/AddressSanitizer.h" | |
33 #include "wtf/Atomics.h" | 32 #include "wtf/Atomics.h" |
34 #include "wtf/CurrentTime.h" | 33 #include "wtf/CurrentTime.h" |
35 #include "wtf/HashSet.h" | 34 #include "wtf/HashSet.h" |
36 #include <algorithm> | 35 #include <algorithm> |
37 #include <limits.h> | 36 #include <limits.h> |
38 #include <limits> | 37 #include <limits> |
39 #include <math.h> | 38 #include <math.h> |
40 | 39 |
41 namespace blink { | 40 namespace blink { |
42 | 41 |
| 42 class TimerHeapReference; |
| 43 |
| 44 // Timers are stored in a heap data structure, used to implement a priority queu
e. |
| 45 // This allows us to efficiently determine which timer needs to fire the soonest
. |
| 46 // Then we set a single shared system timer to fire at that time. |
| 47 // |
| 48 // When a timer's "next fire time" changes, we need to move it around in the pri
ority queue. |
| 49 static Vector<TimerBase*>& threadGlobalTimerHeap() |
| 50 { |
| 51 return PlatformThreadData::current().threadTimers().timerHeap(); |
| 52 } |
| 53 // ---------------- |
| 54 |
| 55 class TimerHeapPointer { |
| 56 public: |
| 57 TimerHeapPointer(TimerBase** pointer) : m_pointer(pointer) { } |
| 58 TimerHeapReference operator*() const; |
| 59 TimerBase* operator->() const { return *m_pointer; } |
| 60 private: |
| 61 TimerBase** m_pointer; |
| 62 }; |
| 63 |
| 64 class TimerHeapReference { |
| 65 public: |
| 66 TimerHeapReference(TimerBase*& reference) : m_reference(reference) { } |
| 67 operator TimerBase*() const { return m_reference; } |
| 68 TimerHeapPointer operator&() const { return &m_reference; } |
| 69 TimerHeapReference& operator=(TimerBase*); |
| 70 TimerHeapReference& operator=(TimerHeapReference); |
| 71 private: |
| 72 TimerBase*& m_reference; |
| 73 }; |
| 74 |
| 75 inline TimerHeapReference TimerHeapPointer::operator*() const |
| 76 { |
| 77 return *m_pointer; |
| 78 } |
| 79 |
| 80 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 81 inline TimerHeapReference& TimerHeapReference::operator=(TimerBase* timer) |
| 82 { |
| 83 m_reference = timer; |
| 84 Vector<TimerBase*>& heap = timer->timerHeap(); |
| 85 if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size()) |
| 86 timer->m_heapIndex = &m_reference - heap.data(); |
| 87 return *this; |
| 88 } |
| 89 |
| 90 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 91 inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference b) |
| 92 { |
| 93 TimerBase* timer = b; |
| 94 return *this = timer; |
| 95 } |
| 96 |
| 97 inline void swap(TimerHeapReference a, TimerHeapReference b) |
| 98 { |
| 99 TimerBase* timerA = a; |
| 100 TimerBase* timerB = b; |
| 101 |
| 102 // Invoke the assignment operator, since that takes care of updating m_heapI
ndex. |
| 103 a = timerB; |
| 104 b = timerA; |
| 105 } |
| 106 |
| 107 // ---------------- |
| 108 |
| 109 // Class to represent iterators in the heap when calling the standard library he
ap algorithms. |
| 110 // Uses a custom pointer and reference type that update indices for pointers in
the heap. |
| 111 class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag,
TimerBase*, ptrdiff_t, TimerHeapPointer, TimerHeapReference> { |
| 112 public: |
| 113 explicit TimerHeapIterator(TimerBase** pointer) : m_pointer(pointer) { check
Consistency(); } |
| 114 |
| 115 TimerHeapIterator& operator++() { checkConsistency(); ++m_pointer; checkCons
istency(); return *this; } |
| 116 TimerHeapIterator operator++(int) { checkConsistency(1); return TimerHeapIte
rator(m_pointer++); } |
| 117 |
| 118 TimerHeapIterator& operator--() { checkConsistency(); --m_pointer; checkCons
istency(); return *this; } |
| 119 TimerHeapIterator operator--(int) { checkConsistency(-1); return TimerHeapIt
erator(m_pointer--); } |
| 120 |
| 121 TimerHeapIterator& operator+=(ptrdiff_t i) { checkConsistency(); m_pointer +
= i; checkConsistency(); return *this; } |
| 122 TimerHeapIterator& operator-=(ptrdiff_t i) { checkConsistency(); m_pointer -
= i; checkConsistency(); return *this; } |
| 123 |
| 124 TimerHeapReference operator*() const { return TimerHeapReference(*m_pointer)
; } |
| 125 TimerHeapReference operator[](ptrdiff_t i) const { return TimerHeapReference
(m_pointer[i]); } |
| 126 TimerBase* operator->() const { return *m_pointer; } |
| 127 |
| 128 private: |
| 129 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 130 void checkConsistency(ptrdiff_t offset = 0) const |
| 131 { |
| 132 ASSERT(m_pointer >= threadGlobalTimerHeap().data()); |
| 133 ASSERT(m_pointer <= threadGlobalTimerHeap().data() + threadGlobalTimerHe
ap().size()); |
| 134 ASSERT_UNUSED(offset, m_pointer + offset >= threadGlobalTimerHeap().data
()); |
| 135 ASSERT_UNUSED(offset, m_pointer + offset <= threadGlobalTimerHeap().data
() + threadGlobalTimerHeap().size()); |
| 136 } |
| 137 |
| 138 friend bool operator==(TimerHeapIterator, TimerHeapIterator); |
| 139 friend bool operator!=(TimerHeapIterator, TimerHeapIterator); |
| 140 friend bool operator<(TimerHeapIterator, TimerHeapIterator); |
| 141 friend bool operator>(TimerHeapIterator, TimerHeapIterator); |
| 142 friend bool operator<=(TimerHeapIterator, TimerHeapIterator); |
| 143 friend bool operator>=(TimerHeapIterator, TimerHeapIterator); |
| 144 |
| 145 friend TimerHeapIterator operator+(TimerHeapIterator, size_t); |
| 146 friend TimerHeapIterator operator+(size_t, TimerHeapIterator); |
| 147 |
| 148 friend TimerHeapIterator operator-(TimerHeapIterator, size_t); |
| 149 friend ptrdiff_t operator-(TimerHeapIterator, TimerHeapIterator); |
| 150 |
| 151 TimerBase** m_pointer; |
| 152 }; |
| 153 |
| 154 inline bool operator==(TimerHeapIterator a, TimerHeapIterator b) { return a.m_po
inter == b.m_pointer; } |
| 155 inline bool operator!=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_po
inter != b.m_pointer; } |
| 156 inline bool operator<(TimerHeapIterator a, TimerHeapIterator b) { return a.m_poi
nter < b.m_pointer; } |
| 157 inline bool operator>(TimerHeapIterator a, TimerHeapIterator b) { return a.m_poi
nter > b.m_pointer; } |
| 158 inline bool operator<=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_po
inter <= b.m_pointer; } |
| 159 inline bool operator>=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_po
inter >= b.m_pointer; } |
| 160 |
| 161 inline TimerHeapIterator operator+(TimerHeapIterator a, size_t b) { return Timer
HeapIterator(a.m_pointer + b); } |
| 162 inline TimerHeapIterator operator+(size_t a, TimerHeapIterator b) { return Timer
HeapIterator(a + b.m_pointer); } |
| 163 |
| 164 inline TimerHeapIterator operator-(TimerHeapIterator a, size_t b) { return Timer
HeapIterator(a.m_pointer - b); } |
| 165 inline ptrdiff_t operator-(TimerHeapIterator a, TimerHeapIterator b) { return a.
m_pointer - b.m_pointer; } |
| 166 |
| 167 // ---------------- |
| 168 |
| 169 class TimerHeapLessThanFunction { |
| 170 public: |
| 171 bool operator()(const TimerBase*, const TimerBase*) const; |
| 172 }; |
| 173 |
| 174 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 175 inline bool TimerHeapLessThanFunction::operator()(const TimerBase* a, const Time
rBase* b) const |
| 176 { |
| 177 // The comparisons below are "backwards" because the heap puts the largest |
| 178 // element first and we want the lowest time to be the first one in the heap
. |
| 179 double aFireTime = a->m_nextFireTime; |
| 180 double bFireTime = b->m_nextFireTime; |
| 181 if (bFireTime != aFireTime) |
| 182 return bFireTime < aFireTime; |
| 183 |
| 184 // We need to look at the difference of the insertion orders instead of comp
aring the two |
| 185 // outright in case of overflow. |
| 186 unsigned difference = a->m_heapInsertionOrder - b->m_heapInsertionOrder; |
| 187 return difference < std::numeric_limits<unsigned>::max() / 2; |
| 188 } |
| 189 |
| 190 // ---------------- |
| 191 |
43 TimerBase::TimerBase() | 192 TimerBase::TimerBase() |
44 : m_nextFireTime(0) | 193 : m_nextFireTime(0) |
45 , m_unalignedNextFireTime(0) | 194 , m_unalignedNextFireTime(0) |
46 , m_repeatInterval(0) | 195 , m_repeatInterval(0) |
47 , m_cancellableTaskFactory(WTF::bind(&TimerBase::run, this)) | 196 , m_heapIndex(-1) |
48 , m_webScheduler(Platform::current()->currentThread()->scheduler()) | 197 , m_cachedThreadGlobalTimerHeap(0) |
49 #if ENABLE(ASSERT) | 198 #if ENABLE(ASSERT) |
50 , m_thread(currentThread()) | 199 , m_thread(currentThread()) |
51 #endif | 200 #endif |
52 { | 201 { |
53 } | 202 } |
54 | 203 |
55 TimerBase::~TimerBase() | 204 TimerBase::~TimerBase() |
56 { | 205 { |
57 stop(); | 206 stop(); |
| 207 ASSERT(!inHeap()); |
58 } | 208 } |
59 | 209 |
60 void TimerBase::start(double nextFireInterval, double repeatInterval, const WebT
raceLocation& caller) | 210 void TimerBase::start(double nextFireInterval, double repeatInterval, const WebT
raceLocation& caller) |
61 { | 211 { |
62 ASSERT(m_thread == currentThread()); | 212 ASSERT(m_thread == currentThread()); |
63 | 213 |
64 m_location = caller; | 214 m_location = caller; |
65 m_repeatInterval = repeatInterval; | 215 m_repeatInterval = repeatInterval; |
66 setNextFireTime(monotonicallyIncreasingTime(), nextFireInterval); | 216 setNextFireTime(monotonicallyIncreasingTime() + nextFireInterval); |
67 } | 217 } |
68 | 218 |
69 void TimerBase::stop() | 219 void TimerBase::stop() |
70 { | 220 { |
71 ASSERT(m_thread == currentThread()); | 221 ASSERT(m_thread == currentThread()); |
72 | 222 |
73 m_repeatInterval = 0; | 223 m_repeatInterval = 0; |
74 m_nextFireTime = 0; | 224 setNextFireTime(0); |
75 m_cancellableTaskFactory.cancel(); | 225 |
| 226 ASSERT(m_nextFireTime == 0); |
| 227 ASSERT(m_repeatInterval == 0); |
| 228 ASSERT(!inHeap()); |
76 } | 229 } |
77 | 230 |
78 double TimerBase::nextFireInterval() const | 231 double TimerBase::nextFireInterval() const |
79 { | 232 { |
80 ASSERT(isActive()); | 233 ASSERT(isActive()); |
81 double current = monotonicallyIncreasingTime(); | 234 double current = monotonicallyIncreasingTime(); |
82 if (m_nextFireTime < current) | 235 if (m_nextFireTime < current) |
83 return 0; | 236 return 0; |
84 return m_nextFireTime - current; | 237 return m_nextFireTime - current; |
85 } | 238 } |
86 | 239 |
87 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 240 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
88 void TimerBase::setNextFireTime(double now, double delay) | 241 inline void TimerBase::checkHeapIndex() const |
| 242 { |
| 243 ASSERT(timerHeap() == threadGlobalTimerHeap()); |
| 244 ASSERT(!timerHeap().isEmpty()); |
| 245 ASSERT(m_heapIndex >= 0); |
| 246 ASSERT(m_heapIndex < static_cast<int>(timerHeap().size())); |
| 247 ASSERT(timerHeap()[m_heapIndex] == this); |
| 248 } |
| 249 |
| 250 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 251 inline void TimerBase::checkConsistency() const |
| 252 { |
| 253 // Timers should be in the heap if and only if they have a non-zero next fir
e time. |
| 254 ASSERT(inHeap() == (m_nextFireTime != 0)); |
| 255 if (inHeap()) |
| 256 checkHeapIndex(); |
| 257 } |
| 258 |
| 259 void TimerBase::heapDecreaseKey() |
| 260 { |
| 261 ASSERT(m_nextFireTime != 0); |
| 262 checkHeapIndex(); |
| 263 TimerBase** heapData = timerHeap().data(); |
| 264 push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapIn
dex + 1), TimerHeapLessThanFunction()); |
| 265 checkHeapIndex(); |
| 266 } |
| 267 |
| 268 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 269 inline void TimerBase::heapDelete() |
| 270 { |
| 271 ASSERT(m_nextFireTime == 0); |
| 272 heapPop(); |
| 273 timerHeap().removeLast(); |
| 274 m_heapIndex = -1; |
| 275 } |
| 276 |
| 277 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 278 void TimerBase::heapDeleteMin() |
| 279 { |
| 280 ASSERT(m_nextFireTime == 0); |
| 281 heapPopMin(); |
| 282 timerHeap().removeLast(); |
| 283 m_heapIndex = -1; |
| 284 } |
| 285 |
| 286 inline void TimerBase::heapIncreaseKey() |
| 287 { |
| 288 ASSERT(m_nextFireTime != 0); |
| 289 heapPop(); |
| 290 heapDecreaseKey(); |
| 291 } |
| 292 |
| 293 inline void TimerBase::heapInsert() |
| 294 { |
| 295 ASSERT(!inHeap()); |
| 296 timerHeap().append(this); |
| 297 m_heapIndex = timerHeap().size() - 1; |
| 298 heapDecreaseKey(); |
| 299 } |
| 300 |
| 301 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 302 inline void TimerBase::heapPop() |
| 303 { |
| 304 // Temporarily force this timer to have the minimum key so we can pop it. |
| 305 double fireTime = m_nextFireTime; |
| 306 m_nextFireTime = -std::numeric_limits<double>::infinity(); |
| 307 heapDecreaseKey(); |
| 308 heapPopMin(); |
| 309 m_nextFireTime = fireTime; |
| 310 } |
| 311 |
| 312 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 313 void TimerBase::heapPopMin() |
| 314 { |
| 315 ASSERT(this == timerHeap().first()); |
| 316 checkHeapIndex(); |
| 317 Vector<TimerBase*>& heap = timerHeap(); |
| 318 TimerBase** heapData = heap.data(); |
| 319 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size
()), TimerHeapLessThanFunction()); |
| 320 checkHeapIndex(); |
| 321 ASSERT(this == timerHeap().last()); |
| 322 } |
| 323 |
| 324 static inline bool parentHeapPropertyHolds(const TimerBase* current, const Vecto
r<TimerBase*>& heap, unsigned currentIndex) |
| 325 { |
| 326 if (!currentIndex) |
| 327 return true; |
| 328 unsigned parentIndex = (currentIndex - 1) / 2; |
| 329 TimerHeapLessThanFunction compareHeapPosition; |
| 330 return compareHeapPosition(current, heap[parentIndex]); |
| 331 } |
| 332 |
| 333 static inline bool childHeapPropertyHolds(const TimerBase* current, const Vector
<TimerBase*>& heap, unsigned childIndex) |
| 334 { |
| 335 if (childIndex >= heap.size()) |
| 336 return true; |
| 337 TimerHeapLessThanFunction compareHeapPosition; |
| 338 return compareHeapPosition(heap[childIndex], current); |
| 339 } |
| 340 |
| 341 bool TimerBase::hasValidHeapPosition() const |
| 342 { |
| 343 ASSERT(m_nextFireTime); |
| 344 if (!inHeap()) |
| 345 return false; |
| 346 // Check if the heap property still holds with the new fire time. If it does
we don't need to do anything. |
| 347 // This assumes that the STL heap is a standard binary heap. In an unlikely
event it is not, the assertions |
| 348 // in updateHeapIfNeeded() will get hit. |
| 349 const Vector<TimerBase*>& heap = timerHeap(); |
| 350 if (!parentHeapPropertyHolds(this, heap, m_heapIndex)) |
| 351 return false; |
| 352 unsigned childIndex1 = 2 * m_heapIndex + 1; |
| 353 unsigned childIndex2 = childIndex1 + 1; |
| 354 return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyH
olds(this, heap, childIndex2); |
| 355 } |
| 356 |
| 357 void TimerBase::updateHeapIfNeeded(double oldTime) |
| 358 { |
| 359 if (m_nextFireTime && hasValidHeapPosition()) |
| 360 return; |
| 361 #if ENABLE(ASSERT) |
| 362 int oldHeapIndex = m_heapIndex; |
| 363 #endif |
| 364 if (!oldTime) |
| 365 heapInsert(); |
| 366 else if (!m_nextFireTime) |
| 367 heapDelete(); |
| 368 else if (m_nextFireTime < oldTime) |
| 369 heapDecreaseKey(); |
| 370 else |
| 371 heapIncreaseKey(); |
| 372 ASSERT(m_heapIndex != oldHeapIndex); |
| 373 ASSERT(!inHeap() || hasValidHeapPosition()); |
| 374 } |
| 375 |
| 376 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
| 377 void TimerBase::setNextFireTime(double newUnalignedTime) |
89 { | 378 { |
90 ASSERT(m_thread == currentThread()); | 379 ASSERT(m_thread == currentThread()); |
91 | 380 |
92 m_unalignedNextFireTime = now + delay; | 381 if (m_unalignedNextFireTime != newUnalignedTime) |
| 382 m_unalignedNextFireTime = newUnalignedTime; |
93 | 383 |
94 double newTime = alignedFireTime(m_unalignedNextFireTime); | 384 // Accessing thread global data is slow. Cache the heap pointer. |
95 if (m_nextFireTime != newTime) { | 385 if (!m_cachedThreadGlobalTimerHeap) |
| 386 m_cachedThreadGlobalTimerHeap = &threadGlobalTimerHeap(); |
| 387 |
| 388 // Keep heap valid while changing the next-fire time. |
| 389 double oldTime = m_nextFireTime; |
| 390 double newTime = alignedFireTime(newUnalignedTime); |
| 391 if (oldTime != newTime) { |
96 m_nextFireTime = newTime; | 392 m_nextFireTime = newTime; |
97 // Round the delay up to the nearest millisecond to be consistant with t
he | 393 static unsigned currentHeapInsertionOrder; |
98 // previous behavior of BlinkPlatformImpl::setSharedTimerFireInterval. | 394 m_heapInsertionOrder = atomicAdd(¤tHeapInsertionOrder, 1); |
99 long long delayMs = static_cast<long long>(ceil((newTime - now) * 1000.0
)); | 395 |
100 if (delayMs < 0) | 396 bool wasFirstTimerInHeap = m_heapIndex == 0; |
101 delayMs = 0; | 397 |
102 m_webScheduler->postTimerTask(m_location, m_cancellableTaskFactory.cance
lAndCreate(), delayMs); | 398 updateHeapIfNeeded(oldTime); |
| 399 |
| 400 bool isFirstTimerInHeap = m_heapIndex == 0; |
| 401 |
| 402 if (wasFirstTimerInHeap || isFirstTimerInHeap) |
| 403 PlatformThreadData::current().threadTimers().updateSharedTimer(); |
103 } | 404 } |
| 405 |
| 406 checkConsistency(); |
104 } | 407 } |
105 | 408 |
106 void TimerBase::run() | 409 void TimerBase::didChangeAlignmentInterval() |
107 { | 410 { |
108 TRACE_EVENT0("blink", "TimerBase::run"); | 411 setNextFireTime(m_unalignedNextFireTime); |
109 ASSERT_WITH_MESSAGE(m_thread == currentThread(), "Timer posted by %s %s was
run on a different thread", m_location.functionName(), m_location.fileName()); | |
110 TRACE_EVENT_SET_SAMPLING_STATE("blink", "BlinkInternal"); | |
111 | |
112 m_nextFireTime = 0; | |
113 // Note: repeating timers drift, but this is preserving the functionality of
the old timer heap. | |
114 // See crbug.com/328700. | |
115 if (m_repeatInterval) | |
116 setNextFireTime(monotonicallyIncreasingTime(), m_repeatInterval); | |
117 fired(); | |
118 TRACE_EVENT_SET_SAMPLING_STATE("blink", "Sleeping"); | |
119 } | |
120 | |
121 void TimerBase::didChangeAlignmentInterval(double now) | |
122 { | |
123 setNextFireTime(now, m_unalignedNextFireTime - now); | |
124 } | 412 } |
125 | 413 |
126 double TimerBase::nextUnalignedFireInterval() const | 414 double TimerBase::nextUnalignedFireInterval() const |
127 { | 415 { |
128 ASSERT(isActive()); | 416 ASSERT(isActive()); |
129 return std::max(m_unalignedNextFireTime - monotonicallyIncreasingTime(), 0.0
); | 417 return std::max(m_unalignedNextFireTime - monotonicallyIncreasingTime(), 0.0
); |
130 } | 418 } |
131 | 419 |
132 } // namespace blink | 420 } // namespace blink |
OLD | NEW |