25a47a68395e825f1b0d616b9710a3e6bb5d78ab
[WebKit-https.git] / Source / WebCore / dom / Microtasks.cpp
1 /*
2  * Copyright (C) 2014 Yoav Weiss (yoav@yoav.ws)
3  * Copyright (C) 2015 Akamai Technologies Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "Microtasks.h"
24
25 #include <wtf/MainThread.h>
26 #include <wtf/NeverDestroyed.h>
27 #include <wtf/SetForScope.h>
28
29 namespace WebCore {
30
31 void Microtask::removeSelfFromQueue(MicrotaskQueue& queue)
32 {
33     queue.remove(*this);
34 }
35
36 MicrotaskQueue::MicrotaskQueue()
37     : m_timer(*this, &MicrotaskQueue::timerFired)
38 {
39 }
40
41 MicrotaskQueue::~MicrotaskQueue() = default;
42
43 MicrotaskQueue& MicrotaskQueue::mainThreadQueue()
44 {
45     ASSERT(isMainThread());
46     static NeverDestroyed<MicrotaskQueue> queue;
47     return queue;
48 }
49
50 MicrotaskQueue& MicrotaskQueue::contextQueue(ScriptExecutionContext& context)
51 {
52     // While main thread has many ScriptExecutionContexts, WorkerGlobalScope and worker thread have
53     // one on one correspondence. The lifetime of MicrotaskQueue is aligned to this semantics.
54     // While main thread MicrotaskQueue is persistently held, worker's MicrotaskQueue is held by
55     // WorkerGlobalScope.
56     if (isMainThread())
57         return mainThreadQueue();
58     return downcast<WorkerGlobalScope>(context).microtaskQueue();
59 }
60
61 void MicrotaskQueue::append(std::unique_ptr<Microtask>&& task)
62 {
63     m_microtaskQueue.append(WTFMove(task));
64
65     m_timer.startOneShot(0_s);
66 }
67
68 void MicrotaskQueue::remove(const Microtask& task)
69 {
70     for (size_t i = 0; i < m_microtaskQueue.size(); ++i) {
71         if (m_microtaskQueue[i].get() == &task) {
72             m_microtaskQueue.remove(i);
73             return;
74         }
75     }
76 }
77
78 void MicrotaskQueue::timerFired()
79 {
80     performMicrotaskCheckpoint();
81 }
82
83 void MicrotaskQueue::performMicrotaskCheckpoint()
84 {
85     if (m_performingMicrotaskCheckpoint)
86         return;
87
88     SetForScope<bool> change(m_performingMicrotaskCheckpoint, true);
89
90     Vector<std::unique_ptr<Microtask>> toKeep;
91     while (!m_microtaskQueue.isEmpty()) {
92         Vector<std::unique_ptr<Microtask>> queue = WTFMove(m_microtaskQueue);
93         for (auto& task : queue) {
94             auto result = task->run();
95             switch (result) {
96             case Microtask::Result::Done:
97                 break;
98             case Microtask::Result::KeepInQueue:
99                 toKeep.append(WTFMove(task));
100                 break;
101             }
102         }
103     }
104
105     m_microtaskQueue = WTFMove(toKeep);
106 }
107
108 } // namespace WebCore