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

8220147: Cherry pick GTK WebKit 2.22.7 changes Reviewed-by: mbilla, kcr
author arajkumar
date Fri, 08 Mar 2019 14:03:47 +0530
parents ab4db0272524
children a1fb556cdd7d
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@11139 40 #if PLATFORM(IOS) || 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 {
kcr@9542 232 // The comparisons below are "backwards" because the heap puts the largest
peterz@3550 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;
kcr@9542 236 // We need to look at the difference of the insertion orders instead of comparing the two
kcr@9542 237 // outright in case of overflow.
arajkumar@11208 238 unsigned difference = aOrder - bOrder;
ant@8798 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@11139 247 #if PLATFORM(IOS)
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());
arajkumar@11208 265 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(canAccessThreadLocalDataForThread(m_thread.get()));
peterz@3550 266 stop();
peterz@3550 267 ASSERT(!inHeap());
arajkumar@11208 268 if (m_heapItem) {
arajkumar@11208 269 m_heapItem->clearTimer();
arajkumar@11208 270 m_heapItem = nullptr;
arajkumar@11208 271 }
ant@8798 272 m_wasDeleted = true;
peterz@3550 273 }
peterz@3550 274
mbilla@10730 275 void TimerBase::start(Seconds nextFireInterval, Seconds repeatInterval)
peterz@3550 276 {
arajkumar@10954 277 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
peterz@3550 278
peterz@3550 279 m_repeatInterval = repeatInterval;
mbilla@10730 280 setNextFireTime(MonotonicTime::now() + nextFireInterval);
peterz@3550 281 }
peterz@3550 282
peterz@3550 283 void TimerBase::stop()
peterz@3550 284 {
arajkumar@10954 285 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
peterz@3550 286
mbilla@10730 287 m_repeatInterval = 0_s;
mbilla@10730 288 setNextFireTime(MonotonicTime { });
peterz@3550 289
arajkumar@11208 290 ASSERT(!static_cast<bool>(nextFireTime()));
mbilla@10730 291 ASSERT(m_repeatInterval == 0_s);
peterz@3550 292 ASSERT(!inHeap());
peterz@3550 293 }
peterz@3550 294
mbilla@10730 295 Seconds TimerBase::nextFireInterval() const
peterz@3550 296 {
peterz@3550 297 ASSERT(isActive());
arajkumar@11208 298 ASSERT(m_heapItem);
mbilla@10730 299 MonotonicTime current = MonotonicTime::now();
arajkumar@11208 300 auto fireTime = nextFireTime();
arajkumar@11208 301 if (fireTime < current)
mbilla@10730 302 return 0_s;
arajkumar@11208 303 return fireTime - current;
peterz@3550 304 }
peterz@3550 305
peterz@3550 306 inline void TimerBase::checkHeapIndex() const
peterz@3550 307 {
arajkumar@11208 308 #if !ASSERT_DISABLED
arajkumar@11208 309 ASSERT(m_heapItem);
arajkumar@11208 310 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 311 ASSERT(&heap == &threadGlobalTimerHeap());
arajkumar@11208 312 ASSERT(!heap.isEmpty());
arajkumar@11208 313 ASSERT(m_heapItem->isInHeap());
arajkumar@11208 314 ASSERT(m_heapItem->heapIndex() < m_heapItem->timerHeap().size());
arajkumar@11208 315 ASSERT(heap[m_heapItem->heapIndex()] == m_heapItem);
arajkumar@11208 316 for (unsigned i = 0, size = heap.size(); i < size; i++)
arajkumar@11208 317 ASSERT(heap[i]->heapIndex() == i);
arajkumar@11208 318 #endif
peterz@3550 319 }
peterz@3550 320
peterz@3550 321 inline void TimerBase::checkConsistency() const
peterz@3550 322 {
peterz@3550 323 // Timers should be in the heap if and only if they have a non-zero next fire time.
arajkumar@11208 324 ASSERT(inHeap() == static_cast<bool>(nextFireTime()));
peterz@3550 325 if (inHeap())
peterz@3550 326 checkHeapIndex();
peterz@3550 327 }
peterz@3550 328
peterz@3550 329 void TimerBase::heapDecreaseKey()
peterz@3550 330 {
arajkumar@11208 331 ASSERT(static_cast<bool>(nextFireTime()));
arajkumar@11208 332 ASSERT(m_heapItem);
peterz@3550 333 checkHeapIndex();
arajkumar@11208 334 auto* heapData = m_heapItem->timerHeap().data();
arajkumar@11208 335 push_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + m_heapItem->heapIndex() + 1), TimerHeapLessThanFunction());
peterz@3550 336 checkHeapIndex();
peterz@3550 337 }
peterz@3550 338
peterz@3550 339 inline void TimerBase::heapDelete()
peterz@3550 340 {
arajkumar@11208 341 ASSERT(!static_cast<bool>(nextFireTime()));
peterz@3550 342 heapPop();
arajkumar@11208 343 m_heapItem->timerHeap().removeLast();
arajkumar@11208 344 m_heapItem->setNotInHeap();
peterz@3550 345 }
peterz@3550 346
peterz@3550 347 void TimerBase::heapDeleteMin()
peterz@3550 348 {
arajkumar@11208 349 ASSERT(!static_cast<bool>(nextFireTime()));
peterz@3550 350 heapPopMin();
arajkumar@11208 351 m_heapItem->timerHeap().removeLast();
arajkumar@11208 352 m_heapItem->setNotInHeap();
peterz@3550 353 }
peterz@3550 354
peterz@3550 355 inline void TimerBase::heapIncreaseKey()
peterz@3550 356 {
arajkumar@11208 357 ASSERT(static_cast<bool>(nextFireTime()));
peterz@3550 358 heapPop();
peterz@3550 359 heapDecreaseKey();
peterz@3550 360 }
peterz@3550 361
peterz@3550 362 inline void TimerBase::heapInsert()
peterz@3550 363 {
peterz@3550 364 ASSERT(!inHeap());
arajkumar@11208 365 ASSERT(m_heapItem);
arajkumar@11208 366 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 367 heap.append(m_heapItem.copyRef());
arajkumar@11208 368 m_heapItem->setHeapIndex(heap.size() - 1);
peterz@3550 369 heapDecreaseKey();
peterz@3550 370 }
peterz@3550 371
peterz@3550 372 inline void TimerBase::heapPop()
peterz@3550 373 {
arajkumar@11208 374 ASSERT(m_heapItem);
peterz@3550 375 // Temporarily force this timer to have the minimum key so we can pop it.
arajkumar@11208 376 MonotonicTime fireTime = m_heapItem->time;
arajkumar@11208 377 m_heapItem->time = -MonotonicTime::infinity();
peterz@3550 378 heapDecreaseKey();
peterz@3550 379 heapPopMin();
arajkumar@11208 380 m_heapItem->time = fireTime;
peterz@3550 381 }
peterz@3550 382
peterz@3550 383 void TimerBase::heapPopMin()
peterz@3550 384 {
arajkumar@11208 385 ASSERT(m_heapItem == m_heapItem->timerHeap().first());
peterz@3550 386 checkHeapIndex();
arajkumar@11208 387 auto& heap = m_heapItem->timerHeap();
arajkumar@11208 388 auto* heapData = heap.data();
peterz@3550 389 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
peterz@3550 390 checkHeapIndex();
arajkumar@11208 391 ASSERT(m_heapItem == m_heapItem->timerHeap().last());
peterz@3550 392 }
peterz@3550 393
arajkumar@11208 394 void TimerBase::heapDeleteNullMin(ThreadTimerHeap& heap)
arajkumar@11208 395 {
arajkumar@11208 396 RELEASE_ASSERT(!heap.first()->hasTimer());
arajkumar@11208 397 heap.first()->time = -MonotonicTime::infinity();
arajkumar@11208 398 auto* heapData = heap.data();
arajkumar@11208 399 pop_heap(TimerHeapIterator(heapData), TimerHeapIterator(heapData + heap.size()), TimerHeapLessThanFunction());
arajkumar@11208 400 heap.removeLast();
arajkumar@11208 401 }
arajkumar@11208 402
arajkumar@11208 403 static inline bool parentHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned currentIndex)
alexey@4236 404 {
alexey@4236 405 if (!currentIndex)
alexey@4236 406 return true;
alexey@4236 407 unsigned parentIndex = (currentIndex - 1) / 2;
arajkumar@11208 408 return TimerHeapLessThanFunction::compare(*current, heap[parentIndex]);
alexey@4236 409 }
alexey@4236 410
arajkumar@11208 411 static inline bool childHeapPropertyHolds(const TimerBase* current, const ThreadTimerHeap& heap, unsigned childIndex)
alexey@4236 412 {
alexey@4236 413 if (childIndex >= heap.size())
alexey@4236 414 return true;
arajkumar@11208 415 return TimerHeapLessThanFunction::compare(heap[childIndex], *current);
alexey@4236 416 }
alexey@4236 417
alexey@4236 418 bool TimerBase::hasValidHeapPosition() const
alexey@4236 419 {
arajkumar@11208 420 ASSERT(nextFireTime());
arajkumar@11208 421 ASSERT(m_heapItem);
alexey@4236 422 if (!inHeap())
alexey@4236 423 return false;
alexey@4236 424 // Check if the heap property still holds with the new fire time. If it does we don't need to do anything.
alexey@4236 425 // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions
alexey@4236 426 // in updateHeapIfNeeded() will get hit.
arajkumar@11208 427 const auto& heap = m_heapItem->timerHeap();
arajkumar@11208 428 unsigned heapIndex = m_heapItem->heapIndex();
arajkumar@11208 429 if (!parentHeapPropertyHolds(this, heap, heapIndex))
alexey@4236 430 return false;
arajkumar@11208 431 unsigned childIndex1 = 2 * heapIndex + 1;
alexey@4236 432 unsigned childIndex2 = childIndex1 + 1;
alexey@4236 433 return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2);
alexey@4236 434 }
alexey@4236 435
mbilla@10730 436 void TimerBase::updateHeapIfNeeded(MonotonicTime oldTime)
alexey@4236 437 {
arajkumar@11208 438 auto fireTime = nextFireTime();
arajkumar@11208 439 if (fireTime && hasValidHeapPosition())
alexey@4236 440 return;
arajkumar@11208 441
arajkumar@11208 442 #if !ASSERT_DISABLED
arajkumar@11208 443 Optional<unsigned> oldHeapIndex;
arajkumar@11208 444 if (m_heapItem->isInHeap())
arajkumar@11208 445 oldHeapIndex = m_heapItem->heapIndex();
alexey@4236 446 #endif
arajkumar@11208 447
alexey@4236 448 if (!oldTime)
alexey@4236 449 heapInsert();
arajkumar@11208 450 else if (!fireTime)
alexey@4236 451 heapDelete();
arajkumar@11208 452 else if (fireTime < oldTime)
alexey@4236 453 heapDecreaseKey();
alexey@4236 454 else
alexey@4236 455 heapIncreaseKey();
arajkumar@11208 456
arajkumar@11208 457 #if !ASSERT_DISABLED
arajkumar@11208 458 Optional<unsigned> newHeapIndex;
arajkumar@11208 459 if (m_heapItem->isInHeap())
arajkumar@11208 460 newHeapIndex = m_heapItem->heapIndex();
arajkumar@11208 461 ASSERT(newHeapIndex != oldHeapIndex);
arajkumar@11208 462 #endif
arajkumar@11208 463
alexey@4236 464 ASSERT(!inHeap() || hasValidHeapPosition());
alexey@4236 465 }
alexey@4236 466
mbilla@10730 467 void TimerBase::setNextFireTime(MonotonicTime newTime)
peterz@3550 468 {
arajkumar@10954 469 ASSERT(canAccessThreadLocalDataForThread(m_thread.get()));
arajkumar@11139 470 RELEASE_ASSERT(canAccessThreadLocalDataForThread(m_thread.get()) || shouldSuppressThreadSafetyCheck());
arajkumar@10954 471 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!m_wasDeleted);
peterz@3550 472
arajkumar@10587 473 if (m_unalignedNextFireTime != newTime)
arajkumar@10587 474 m_unalignedNextFireTime = newTime;
alexey@4236 475
peterz@3550 476 // Keep heap valid while changing the next-fire time.
arajkumar@11208 477 MonotonicTime oldTime = nextFireTime();
arajkumar@10587 478 // Don't realign zero-delay timers.
arajkumar@10587 479 if (newTime) {
mbilla@10730 480 if (auto newAlignedTime = alignedFireTime(newTime))
mbilla@10730 481 newTime = newAlignedTime.value();
arajkumar@10587 482 }
arajkumar@10587 483
peterz@3550 484 if (oldTime != newTime) {
kcr@9800 485 // FIXME: This should be part of ThreadTimers, or another per-thread structure.
kcr@9800 486 static std::atomic<unsigned> currentHeapInsertionOrder;
arajkumar@11208 487 auto newOrder = currentHeapInsertionOrder++;
peterz@3550 488
arajkumar@11208 489 if (!m_heapItem)
arajkumar@11208 490 m_heapItem = ThreadTimerHeapItem::create(*this, newTime, 0);
arajkumar@11208 491 m_heapItem->time = newTime;
arajkumar@11208 492 m_heapItem->insertionOrder = newOrder;
arajkumar@11208 493
arajkumar@11208 494 bool wasFirstTimerInHeap = m_heapItem->isFirstInHeap();
peterz@3550 495
alexey@4236 496 updateHeapIfNeeded(oldTime);
peterz@3550 497
arajkumar@11208 498 bool isFirstTimerInHeap = m_heapItem->isFirstInHeap();
peterz@3550 499
peterz@3550 500 if (wasFirstTimerInHeap || isFirstTimerInHeap)
peterz@3550 501 threadGlobalData().threadTimers().updateSharedTimer();
peterz@3550 502 }
peterz@3550 503
peterz@3550 504 checkConsistency();
peterz@3550 505 }
peterz@3550 506
peterz@3550 507 void TimerBase::fireTimersInNestedEventLoop()
peterz@3550 508 {
peterz@3550 509 // Redirect to ThreadTimers.
peterz@3550 510 threadGlobalData().threadTimers().fireTimersInNestedEventLoop();
peterz@3550 511 }
peterz@3550 512
alexey@4236 513 void TimerBase::didChangeAlignmentInterval()
alexey@4236 514 {
alexey@4236 515 setNextFireTime(m_unalignedNextFireTime);
alexey@4236 516 }
alexey@4236 517
mbilla@10730 518 Seconds TimerBase::nextUnalignedFireInterval() const
alexey@4236 519 {
alexey@4236 520 ASSERT(isActive());
mbilla@10730 521 return std::max(m_unalignedNextFireTime - MonotonicTime::now(), 0_s);
alexey@4236 522 }
alexey@4236 523
peterz@3550 524 } // namespace WebCore
peterz@3550 525