annotate modules/javafx.web/src/main/native/Source/WebCore/platform/Timer.cpp @ 11342:d7d63c79d24f

Merge
author kcr
date Tue, 10 Sep 2019 08:52:49 -0700
parents db2c977a840b
children
rev   line source
peterz@3550 1 /*
peterz@3550 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
peterz@3550 3 * Copyright (C) 2009 Google Inc. All rights reserved.
peterz@3550 4 *
peterz@3550 5 * Redistribution and use in source and binary forms, with or without
peterz@3550 6 * modification, are permitted provided that the following conditions
peterz@3550 7 * are met:
peterz@3550 8 * 1. Redistributions of source code must retain the above copyright
peterz@3550 9 * notice, this list of conditions and the following disclaimer.
peterz@3550 10 * 2. Redistributions in binary form must reproduce the above copyright
peterz@3550 11 * notice, this list of conditions and the following disclaimer in the
peterz@3550 12 * documentation and/or other materials provided with the distribution.
peterz@3550 13 *
kcr@9800 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
peterz@3550 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
peterz@3550 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
kcr@9800 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
peterz@3550 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
peterz@3550 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
peterz@3550 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
peterz@3550 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
peterz@3550 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
peterz@3550 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
kcr@9542 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
peterz@3550 25 */
peterz@3550 26
peterz@3550 27 #include "config.h"
peterz@3550 28 #include "Timer.h"
peterz@3550 29
arajkumar@11139 30 #include "RuntimeApplicationChecks.h"
peterz@3550 31 #include "SharedTimer.h"
peterz@3550 32 #include "ThreadGlobalData.h"
peterz@3550 33 #include "ThreadTimers.h"
peterz@3550 34 #include <limits.h>
peterz@3550 35 #include <limits>
peterz@3550 36 #include <math.h>
ant@8798 37 #include <wtf/MainThread.h>
peterz@3550 38 #include <wtf/Vector.h>
peterz@3550 39
arajkumar@11290 40 #if PLATFORM(IOS_FAMILY) || PLATFORM(MAC)
arajkumar@11139 41 #include <wtf/spi/darwin/dyldSPI.h>
arajkumar@11139 42 #endif
arajkumar@11139 43
peterz@3550 44 namespace WebCore {
peterz@3550 45
peterz@3550 46 class TimerHeapReference;
peterz@3550 47
peterz@3550 48 // Timers are stored in a heap data structure, used to implement a priority queue.
peterz@3550 49 // This allows us to efficiently determine which timer needs to fire the soonest.
peterz@3550 50 // Then we set a single shared system timer to fire at that time.
peterz@3550 51 //
peterz@3550 52 // When a timer's "next fire time" changes, we need to move it around in the priority queue.
arajkumar@11208 53 #if !ASSERT_DISABLED
arajkumar@11208 54 static ThreadTimerHeap& threadGlobalTimerHeap()
peterz@3550 55 {
peterz@3550 56 return threadGlobalData().threadTimers().timerHeap();
peterz@3550 57 }
arajkumar@11208 58 #endif
arajkumar@11208 59
arajkumar@11208 60 inline ThreadTimerHeapItem::ThreadTimerHeapItem(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
arajkumar@11208 61 : time(time)
arajkumar@11208 62 , insertionOrder(insertionOrder)
arajkumar@11208 63 , m_threadTimers(threadGlobalData().threadTimers())
arajkumar@11208 64 , m_timer(&timer)
arajkumar@11208 65 {
arajkumar@11208 66 ASSERT(m_timer);
arajkumar@11208 67 }
arajkumar@11208 68
arajkumar@11208 69 inline RefPtr<ThreadTimerHeapItem> ThreadTimerHeapItem::create(TimerBase& timer, MonotonicTime time, unsigned insertionOrder)
arajkumar@11208 70 {
arajkumar@11208 71 return adoptRef(*new ThreadTimerHeapItem { timer, time, insertionOrder });
arajkumar@11208 72 }
arajkumar@11208 73
peterz@3550 74 // ----------------
peterz@3550 75
peterz@3550 76 class TimerHeapPointer {
peterz@3550 77 public:
arajkumar@11208 78 TimerHeapPointer(RefPtr<ThreadTimerHeapItem>* pointer)
arajkumar@11208 79 : m_pointer(pointer)
arajkumar@11208 80 { }
arajkumar@11208 81
peterz@3550 82 TimerHeapReference operator*() const;
arajkumar@11208 83 RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
peterz@3550 84 private:
arajkumar@11208 85 RefPtr<ThreadTimerHeapItem>* m_pointer;
peterz@3550 86 };
peterz@3550 87
peterz@3550 88 class TimerHeapReference {
peterz@3550 89 public:
arajkumar@11208 90 TimerHeapReference(RefPtr<ThreadTimerHeapItem>& reference)
arajkumar@11208 91 : m_reference(reference)
arajkumar@11208 92 { }
arajkumar@11208 93
arajkumar@11208 94 TimerHeapReference(const TimerHeapReference& other)
arajkumar@11208 95 : m_reference(other.m_reference)
arajkumar@11208 96 { }
arajkumar@11208 97
arajkumar@11208 98 operator RefPtr<ThreadTimerHeapItem>&() const { return m_reference; }
peterz@3550 99 TimerHeapPointer operator&() const { return &m_reference; }
arajkumar@11208 100 TimerHeapReference& operator=(TimerHeapReference&&);
arajkumar@11208 101 TimerHeapReference& operator=(RefPtr<ThreadTimerHeapItem>&&);
arajkumar@11208 102
arajkumar@11208 103 void swap(TimerHeapReference& other);
arajkumar@11208 104
arajkumar@11208 105 void updateHeapIndex();
arajkumar@11208 106
peterz@3550 107 private:
arajkumar@11208 108 RefPtr<ThreadTimerHeapItem>& m_reference;
arajkumar@11208 109
arajkumar@11208 110 friend void swap(TimerHeapReference a, TimerHeapReference b);
peterz@3550 111 };
peterz@3550 112
peterz@3550 113 inline TimerHeapReference TimerHeapPointer::operator*() const
peterz@3550 114 {
arajkumar@11208 115 return TimerHeapReference { *m_pointer };
peterz@3550 116 }
peterz@3550 117
arajkumar@11208 118 inline TimerHeapReference& TimerHeapReference::operator=(TimerHeapReference&& other)
peterz@3550 119 {
arajkumar@11208 120 m_reference = WTFMove(other.m_reference);
arajkumar@11208 121 updateHeapIndex();
peterz@3550 122 return *this;
peterz@3550 123 }
peterz@3550 124
arajkumar@11208 125 inline TimerHeapReference& TimerHeapReference::operator=(RefPtr<ThreadTimerHeapItem>&& item)
peterz@3550 126 {
arajkumar@11208 127 m_reference = WTFMove(item);
arajkumar@11208 128 updateHeapIndex();
arajkumar@11208 129 return *this;
arajkumar@11208 130 }
arajkumar@11208 131
arajkumar@11208 132 inline void TimerHeapReference::swap(TimerHeapReference& other)
arajkumar@11208 133 {
arajkumar@11208 134 m_reference.swap(other.m_reference);
arajkumar@11208 135 updateHeapIndex();
arajkumar@11208 136 other.updateHeapIndex();
arajkumar@11208 137 }
arajkumar@11208 138
arajkumar@11208 139 inline void TimerHeapReference::updateHeapIndex()
arajkumar@11208 140 {
arajkumar@11208 141 auto& heap = m_reference->timerHeap();
arajkumar@11208 142 if (&m_reference >= heap.data() && &m_reference < heap.data() + heap.size())
arajkumar@11208 143 m_reference->setHeapIndex(&m_reference - heap.data());
peterz@3550 144 }
peterz@3550 145
peterz@3550 146 inline void swap(TimerHeapReference a, TimerHeapReference b)
peterz@3550 147 {
arajkumar@11208 148 a.swap(b);
peterz@3550 149 }
peterz@3550 150
peterz@3550 151 // ----------------
peterz@3550 152
peterz@3550 153 // Class to represent iterators in the heap when calling the standard library heap algorithms.
peterz@3550 154 // Uses a custom pointer and reference type that update indices for pointers in the heap.
arajkumar@11208 155 class TimerHeapIterator : public std::iterator<std::random_access_iterator_tag, RefPtr<ThreadTimerHeapItem>, ptrdiff_t, TimerHeapPointer, TimerHeapReference> {
peterz@3550 156 public:
arajkumar@11208 157 explicit TimerHeapIterator(RefPtr<ThreadTimerHeapItem>* pointer) : m_pointer(pointer) { checkConsistency(); }
peterz@3550 158
peterz@3550 159 TimerHeapIterator& operator++() { checkConsistency(); ++m_pointer; checkConsistency(); return *this; }
peterz@3550 160 TimerHeapIterator operator++(int) { checkConsistency(1); return TimerHeapIterator(m_pointer++); }
peterz@3550 161
peterz@3550 162 TimerHeapIterator& operator--() { checkConsistency(); --m_pointer; checkConsistency(); return *this; }
peterz@3550 163 TimerHeapIterator operator--(int) { checkConsistency(-1); return TimerHeapIterator(m_pointer--); }
peterz@3550 164
peterz@3550 165 TimerHeapIterator& operator+=(ptrdiff_t i) { checkConsistency(); m_pointer += i; checkConsistency(); return *this; }
peterz@3550 166 TimerHeapIterator& operator-=(ptrdiff_t i) { checkConsistency(); m_pointer -= i; checkConsistency(); return *this; }
peterz@3550 167
peterz@3550 168 TimerHeapReference operator*() const { return TimerHeapReference(*m_pointer); }
peterz@3550 169 TimerHeapReference operator[](ptrdiff_t i) const { return TimerHeapReference(m_pointer[i]); }
arajkumar@11208 170 RefPtr<ThreadTimerHeapItem>& operator->() const { return *m_pointer; }
peterz@3550 171
peterz@3550 172 private:
peterz@3550 173 void checkConsistency(ptrdiff_t offset = 0) const
peterz@3550 174 {
alexey@4236 175 ASSERT(m_pointer >= threadGlobalTimerHeap().data());
alexey@4236 176 ASSERT(m_pointer <= threadGlobalTimerHeap().data() + threadGlobalTimerHeap().size());
alexey@4236 177 ASSERT_UNUSED(offset, m_pointer + offset >= threadGlobalTimerHeap().data());
alexey@4236 178 ASSERT_UNUSED(offset, m_pointer + offset <= threadGlobalTimerHeap().data() + threadGlobalTimerHeap().size());
peterz@3550 179 }
peterz@3550 180
peterz@3550 181 friend bool operator==(TimerHeapIterator, TimerHeapIterator);
peterz@3550 182 friend bool operator!=(TimerHeapIterator, TimerHeapIterator);
peterz@3550 183 friend bool operator<(TimerHeapIterator, TimerHeapIterator);
peterz@3550 184 friend bool operator>(TimerHeapIterator, TimerHeapIterator);
peterz@3550 185 friend bool operator<=(TimerHeapIterator, TimerHeapIterator);
peterz@3550 186 friend bool operator>=(TimerHeapIterator, TimerHeapIterator);
kcr@9542 187
peterz@3550 188 friend TimerHeapIterator operator+(TimerHeapIterator, size_t);
peterz@3550 189 friend TimerHeapIterator operator+(size_t, TimerHeapIterator);
kcr@9542 190
peterz@3550 191 friend TimerHeapIterator operator-(TimerHeapIterator, size_t);
peterz@3550 192 friend ptrdiff_t operator-(TimerHeapIterator, TimerHeapIterator);
peterz@3550 193
arajkumar@11208 194 RefPtr<ThreadTimerHeapItem>* m_pointer;
peterz@3550 195 };
peterz@3550 196
peterz@3550 197 inline bool operator==(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer == b.m_pointer; }
peterz@3550 198 inline bool operator!=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer != b.m_pointer; }
peterz@3550 199 inline bool operator<(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer < b.m_pointer; }
peterz@3550 200 inline bool operator>(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer > b.m_pointer; }
peterz@3550 201 inline bool operator<=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer <= b.m_pointer; }
peterz@3550 202 inline bool operator>=(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer >= b.m_pointer; }
peterz@3550 203
peterz@3550 204 inline TimerHeapIterator operator+(TimerHeapIterator a, size_t b) { return TimerHeapIterator(a.m_pointer + b); }
peterz@3550 205 inline TimerHeapIterator operator+(size_t a, TimerHeapIterator b) { return TimerHeapIterator(a + b.m_pointer); }
peterz@3550 206
peterz@3550 207 inline TimerHeapIterator operator-(TimerHeapIterator a, size_t b) { return TimerHeapIterator(a.m_pointer - b); }
peterz@3550 208 inline ptrdiff_t operator-(TimerHeapIterator a, TimerHeapIterator b) { return a.m_pointer - b.m_pointer; }
peterz@3550 209
peterz@3550 210 // ----------------
peterz@3550 211
peterz@3550 212 class TimerHeapLessThanFunction {
peterz@3550 213 public:
arajkumar@11208 214 static bool compare(const TimerBase& a, const RefPtr<ThreadTimerHeapItem>& b)
arajkumar@11208 215 {
arajkumar@11208 216 return compare(a.m_heapItem->time, a.m_heapItem->insertionOrder, b->time, b->insertionOrder);
arajkumar@11208 217 }
peterz@3550 218
arajkumar@11208 219 static bool compare(const RefPtr<ThreadTimerHeapItem>& a, const TimerBase& b)
arajkumar@11208 220 {
arajkumar@11208 221 return compare(a->time, a->insertionOrder, b.m_heapItem->time, b.m_heapItem->insertionOrder);
arajkumar@11208 222 }
arajkumar@11208 223
arajkumar@11208 224 bool operator()(const RefPtr<ThreadTimerHeapItem>& a, const RefPtr<ThreadTimerHeapItem>& b) const
arajkumar@11208 225 {
arajkumar@11208 226 return compare(a->time, a->insertionOrder, b->time, b->insertionOrder);
arajkumar@11208 227 }
arajkumar@11208 228
arajkumar@11208 229 private:
arajkumar@11208 230 static bool compare(MonotonicTime aTime, unsigned aOrder, MonotonicTime bTime, unsigned bOrder)
arajkumar@11208 231 {
arajkumar@11290 232 // The comparisons below are "backwards" because the heap puts the largest
arajkumar@11290 233 // element first and we want the lowest time to be the first one in the heap.
arajkumar@11208 234 if (bTime != aTime)
arajkumar@11208 235 return bTime < aTime;
arajkumar@11290 236 // We need to look at the difference of the insertion orders instead of comparing the two
arajkumar@11290 237 // outright in case of overflow.
arajkumar@11208 238 unsigned difference = aOrder - bOrder;
arajkumar@11290 239 return difference < std::numeric_limits<unsigned>::max() / 2;
arajkumar@11208 240 }
arajkumar@11208 241 };
peterz@3550 242
peterz@3550 243 // ----------------
peterz@3550 244
arajkumar@11139 245 static bool shouldSuppressThreadSafetyCheck()
arajkumar@11139 246 {
arajkumar@11290 247 #if PLATFORM(IOS_FAMILY)
arajkumar@11139 248 return WebThreadIsEnabled() || applicationSDKVersion() < DYLD_IOS_VERSION_12_0;
arajkumar@11139 249 #elif PLATFORM(MAC)
arajkumar@11139 250 return !isInWebProcess() && applicationSDKVersion() < DYLD_MACOSX_VERSION_10_14;
arajkumar@11139 251 #else
arajkumar@11139 252 return false;
arajkumar@11139 253 #endif
arajkumar@11139 254 }
arajkumar@11139 255
peterz@3550 256 TimerBase::TimerBase()
arajkumar@11208 257 : m_wasDeleted(false)
peterz@3550 258 {
peterz@3550 259 }
peterz@3550 260
peterz@3550 261 TimerBase::~TimerBase()
peterz@3550 262 {
arajkumar@11139 263 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
arajkumar@11139 264 RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck());
peterz@3550 265 stop();
peterz@3550 266 ASSERT(!inHeap());
arajkumar@11208 267 if (m_heapItem) {
arajkumar@11208 268 m_heapItem->clearTimer();
arajkumar@11208 269 m_heapItem = nullptr;
arajkumar@11208 270 }
ant@8798 271 m_wasDeleted = true;
peterz@3550 272 }
peterz@3550 273
mbilla@10730 274 void TimerBase::start(Seconds nextFireInterval, Seconds repeatInterval)
peterz@3550 275 {
arajkumar@10954 276 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
peterz@3550 277
peterz@3550 278 m_repeatInterval = repeatInterval;
mbilla@10730 279 setNextFireTime(MonotonicTime::now() + nextFireInterval);
peterz@3550 280 }
peterz@3550 281
peterz@3550 282 void TimerBase::stop()
peterz@3550 283 {
arajkumar@10954 284 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
peterz@3550 285
mbilla@10730 286 m_repeatInterval = 0_s;
mbilla@10730 287 setNextFireTime(MonotonicTime { });
peterz@3550 288
arajkumar@11208 289 ASSERT(!static_cast<bool>(nextFireTime()));
mbilla@10730 290 ASSERT(m_repeatInterval == 0_s);
peterz@3550 291 ASSERT(!inHeap());
peterz@3550 292 }
peterz@3550 293
mbilla@10730 294 Seconds TimerBase::nextFireInterval() const
peterz@3550 295 {
peterz@3550 296 ASSERT(isActive());
arajkumar@11208 297 ASSERT(m_heapItem);
mbilla@10730 298 MonotonicTime current = MonotonicTime::now();
arajkumar@11208 299 auto fireTime = nextFireTime();
arajkumar@11208 300 if (fireTime < current)
mbilla@10730 301 return 0_s;
arajkumar@11208 302 return fireTime - current;
peterz@3550 303 }
peterz@3550 304
peterz@3550 305 inline void TimerBase::checkHeapIndex() const
peterz@3550 306 {
arajkumar@11208 307 #if !ASSERT_DISABLED
arajkumar@11208 308 ASSERT(m_heapItem);
arajkumar@11208 309 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 310 ASSERT(&heap == &threadGlobalTimerHeap());
arajkumar@11208 311 ASSERT(!heap.isEmpty());
arajkumar@11208 312 ASSERT(m_heapItem->isInHeap());
arajkumar@11208 313 ASSERT(m_heapItem->heapIndex() < m_heapItem->timerHeap().size());
arajkumar@11208 314 ASSERT(heap[m_heapItem->heapIndex()] == m_heapItem);
arajkumar@11208 315 for (unsigned i = 0, size = heap.size(); i < size; i++)
arajkumar@11208 316 ASSERT(heap[i]->heapIndex() == i);
arajkumar@11208 317 #endif
peterz@3550 318 }
peterz@3550 319
peterz@3550 320 inline void TimerBase::checkConsistency() const
peterz@3550 321 {
peterz@3550 322 // Timers should be in the heap if and only if they have a non-zero next fire time.
arajkumar@11208 323 ASSERT(inHeap() == static_cast<bool>(nextFireTime()));
peterz@3550 324 if (inHeap())
peterz@3550 325 checkHeapIndex();
peterz@3550 326 }
peterz@3550 327
peterz@3550 328 void TimerBase::heapDecreaseKey()
peterz@3550 329 {
arajkumar@11208 330 ASSERT(static_cast<bool>(nextFireTime()));
arajkumar@11208 331 ASSERT(m_heapItem);
peterz@3550 332 checkHeapIndex();
arajkumar@11208 333 auto* heapData = m_heapItem->timerHeap().data();
arajkumar@11208 334 push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapItem->heapIndex() + 1), TimerHeapLessThanFunction());
peterz@3550 335 checkHeapIndex();
peterz@3550 336 }
peterz@3550 337
peterz@3550 338 inline void TimerBase::heapDelete()
peterz@3550 339 {
arajkumar@11208 340 ASSERT(!static_cast<bool>(nextFireTime()));
peterz@3550 341 heapPop();
arajkumar@11208 342 m_heapItem->timerHeap().removeLast();
arajkumar@11208 343 m_heapItem->setNotInHeap();
peterz@3550 344 }
peterz@3550 345
peterz@3550 346 void TimerBase::heapDeleteMin()
peterz@3550 347 {
arajkumar@11208 348 ASSERT(!static_cast<bool>(nextFireTime()));
peterz@3550 349 heapPopMin();
arajkumar@11208 350 m_heapItem->timerHeap().removeLast();
arajkumar@11208 351 m_heapItem->setNotInHeap();
peterz@3550 352 }
peterz@3550 353
peterz@3550 354 inline void TimerBase::heapIncreaseKey()
peterz@3550 355 {
arajkumar@11208 356 ASSERT(static_cast<bool>(nextFireTime()));
peterz@3550 357 heapPop();
peterz@3550 358 heapDecreaseKey();
peterz@3550 359 }
peterz@3550 360
peterz@3550 361 inline void TimerBase::heapInsert()
peterz@3550 362 {
peterz@3550 363 ASSERT(!inHeap());
arajkumar@11208 364 ASSERT(m_heapItem);
arajkumar@11208 365 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 366 heap.append(m_heapItem.copyRef());
arajkumar@11208 367 m_heapItem->setHeapIndex(heap.size() - 1);
peterz@3550 368 heapDecreaseKey();
peterz@3550 369 }
peterz@3550 370
peterz@3550 371 inline void TimerBase::heapPop()
peterz@3550 372 {
arajkumar@11208 373 ASSERT(m_heapItem);
peterz@3550 374 // Temporarily force this timer to have the minimum key so we can pop it.
arajkumar@11208 375 MonotonicTime fireTime = m_heapItem->time;
arajkumar@11208 376 m_heapItem->time = -MonotonicTime::infinity();
peterz@3550 377 heapDecreaseKey();
peterz@3550 378 heapPopMin();
arajkumar@11208 379 m_heapItem->time = fireTime;
peterz@3550 380 }
peterz@3550 381
peterz@3550 382 void TimerBase::heapPopMin()
peterz@3550 383 {
arajkumar@11208 384 ASSERT(m_heapItem == m_heapItem->timerHeap().first());
peterz@3550 385 checkHeapIndex();
arajkumar@11208 386 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 387 auto* heapData = heap.data();
peterz@3550 388 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
peterz@3550 389 checkHeapIndex();
arajkumar@11208 390 ASSERT(m_heapItem == m_heapItem->timerHeap().last());
peterz@3550 391 }
peterz@3550 392
arajkumar@11208 393 void TimerBase::heapDeleteNullMin(ThreadTimerHeap& heap)
arajkumar@11208 394 {
arajkumar@11208 395 RELEASE_ASSERT(!heap.first()->hasTimer());
arajkumar@11208 396 heap.first()->time = -MonotonicTime::infinity();
arajkumar@11208 397 auto* heapData = heap.data();
arajkumar@11208 398 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
arajkumar@11208 399 heap.removeLast();
arajkumar@11208 400 }
arajkumar@11208 401
arajkumar@11208 402 static inline bool parentHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned currentIndex)
alexey@4236 403 {
alexey@4236 404 if (!currentIndex)
alexey@4236 405 return true;
alexey@4236 406 unsigned parentIndex = (currentIndex - 1) / 2;
arajkumar@11208 407 return TimerHeapLessThanFunction::compare(*current, heap[parentIndex]);
alexey@4236 408 }
alexey@4236 409
arajkumar@11208 410 static inline bool childHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned childIndex)
alexey@4236 411 {
alexey@4236 412 if (childIndex >= heap.size())
alexey@4236 413 return true;
arajkumar@11208 414 return TimerHeapLessThanFunction::compare(heap[childIndex], *current);
alexey@4236 415 }
alexey@4236 416
alexey@4236 417 bool TimerBase::hasValidHeapPosition() const
alexey@4236 418 {
arajkumar@11208 419 ASSERT(nextFireTime());
arajkumar@11208 420 ASSERT(m_heapItem);
alexey@4236 421 if (!inHeap())
alexey@4236 422 return false;
alexey@4236 423 // Check if the heap property still holds with the new fire time. If it does we don't need to do anything.
alexey@4236 424 // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions
alexey@4236 425 // in updateHeapIfNeeded() will get hit.
arajkumar@11208 426 const auto& heap = m_heapItem->timerHeap();
arajkumar@11208 427 unsigned heapIndex = m_heapItem->heapIndex();
arajkumar@11208 428 if (!parentHeapPropertyHolds(this, heap, heapIndex))
alexey@4236 429 return false;
arajkumar@11208 430 unsigned childIndex1 = 2 * heapIndex + 1;
alexey@4236 431 unsigned childIndex2 = childIndex1 + 1;
alexey@4236 432 return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2);
alexey@4236 433 }
alexey@4236 434
mbilla@10730 435 void TimerBase::updateHeapIfNeeded(MonotonicTime oldTime)
alexey@4236 436 {
arajkumar@11208 437 auto fireTime = nextFireTime();
arajkumar@11208 438 if (fireTime && hasValidHeapPosition())
alexey@4236 439 return;
arajkumar@11208 440
arajkumar@11208 441 #if !ASSERT_DISABLED
arajkumar@11208 442 Optional<unsigned> oldHeapIndex;
arajkumar@11208 443 if (m_heapItem->isInHeap())
arajkumar@11208 444 oldHeapIndex = m_heapItem->heapIndex();
alexey@4236 445 #endif
arajkumar@11208 446
alexey@4236 447 if (!oldTime)
alexey@4236 448 heapInsert();
arajkumar@11208 449 else if (!fireTime)
alexey@4236 450 heapDelete();
arajkumar@11208 451 else if (fireTime < oldTime)
alexey@4236 452 heapDecreaseKey();
alexey@4236 453 else
alexey@4236 454 heapIncreaseKey();
arajkumar@11208 455
arajkumar@11208 456 #if !ASSERT_DISABLED
arajkumar@11208 457 Optional<unsigned> newHeapIndex;
arajkumar@11208 458 if (m_heapItem->isInHeap())
arajkumar@11208 459 newHeapIndex = m_heapItem->heapIndex();
arajkumar@11208 460 ASSERT(newHeapIndex != oldHeapIndex);
arajkumar@11208 461 #endif
arajkumar@11208 462
alexey@4236 463 ASSERT(!inHeap() || hasValidHeapPosition());
alexey@4236 464 }
alexey@4236 465
mbilla@10730 466 void TimerBase::setNextFireTime(MonotonicTime newTime)
peterz@3550 467 {
arajkumar@10954 468 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
arajkumar@11139 469 RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck());
arajkumar@10954 470 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!m_wasDeleted);
peterz@3550 471
arajkumar@10587 472 if (m_unalignedNextFireTime != newTime)
arajkumar@10587 473 m_unalignedNextFireTime = newTime;
alexey@4236 474
peterz@3550 475 // Keep heap valid while changing the next-fire time.
arajkumar@11208 476 MonotonicTime oldTime = nextFireTime();
arajkumar@10587 477 // Don't realign zero-delay timers.
arajkumar@10587 478 if (newTime) {
mbilla@10730 479 if (auto newAlignedTime = alignedFireTime(newTime))
mbilla@10730 480 newTime = newAlignedTime.value();
arajkumar@10587 481 }
arajkumar@10587 482
peterz@3550 483 if (oldTime != newTime) {
kcr@9800 484 // FIXME: This should be part of ThreadTimers, or another per-thread structure.
kcr@9800 485 static std::atomic<unsigned> currentHeapInsertionOrder;
arajkumar@11208 486 auto newOrder = currentHeapInsertionOrder++;
peterz@3550 487
arajkumar@11208 488 if (!m_heapItem)
arajkumar@11208 489 m_heapItem = ThreadTimerHeapItem::create(*this, newTime, 0);
arajkumar@11208 490 m_heapItem->time = newTime;
arajkumar@11208 491 m_heapItem->insertionOrder = newOrder;
arajkumar@11208 492
arajkumar@11208 493 bool wasFirstTimerInHeap = m_heapItem->isFirstInHeap();
peterz@3550 494
alexey@4236 495 updateHeapIfNeeded(oldTime);
peterz@3550 496
arajkumar@11208 497 bool isFirstTimerInHeap = m_heapItem->isFirstInHeap();
peterz@3550 498
peterz@3550 499 if (wasFirstTimerInHeap || isFirstTimerInHeap)
peterz@3550 500 threadGlobalData().threadTimers().updateSharedTimer();
peterz@3550 501 }
peterz@3550 502
peterz@3550 503 checkConsistency();
peterz@3550 504 }
peterz@3550 505
peterz@3550 506 void TimerBase::fireTimersInNestedEventLoop()
peterz@3550 507 {
peterz@3550 508 // Redirect to ThreadTimers.
peterz@3550 509 threadGlobalData().threadTimers().fireTimersInNestedEventLoop();
peterz@3550 510 }
peterz@3550 511
alexey@4236 512 void TimerBase::didChangeAlignmentInterval()
alexey@4236 513 {
alexey@4236 514 setNextFireTime(m_unalignedNextFireTime);
alexey@4236 515 }
alexey@4236 516
mbilla@10730 517 Seconds TimerBase::nextUnalignedFireInterval() const
alexey@4236 518 {
alexey@4236 519 ASSERT(isActive());
mbilla@10730 520 return std::max(m_unalignedNextFireTime - MonotonicTime::now(), 0_s);
alexey@4236 521 }
alexey@4236 522
peterz@3550 523 } // namespace WebCore
peterz@3550 524