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 "WorkerGlobalScope.h"
26#include <wtf/MainThread.h>
27#include <wtf/NeverDestroyed.h>
28#include <wtf/SetForScope.h>
29
30namespace WebCore {
31
32void Microtask::removeSelfFromQueue(MicrotaskQueue& queue)
33{
34 queue.remove(*this);
35}
36
37MicrotaskQueue::MicrotaskQueue()
38 : m_timer(*this, &MicrotaskQueue::timerFired)
39{
40}
41
42MicrotaskQueue::~MicrotaskQueue() = default;
43
44MicrotaskQueue& MicrotaskQueue::mainThreadQueue()
45{
46 ASSERT(isMainThread());
47 static NeverDestroyed<MicrotaskQueue> queue;
48 return queue;
49}
50
51MicrotaskQueue& MicrotaskQueue::contextQueue(ScriptExecutionContext& context)
52{
53 // While main thread has many ScriptExecutionContexts, WorkerGlobalScope and worker thread have
54 // one on one correspondence. The lifetime of MicrotaskQueue is aligned to this semantics.
55 // While main thread MicrotaskQueue is persistently held, worker's MicrotaskQueue is held by
56 // WorkerGlobalScope.
57 if (isMainThread())
58 return mainThreadQueue();
59 return downcast<WorkerGlobalScope>(context).microtaskQueue();
60}
61
62void MicrotaskQueue::append(std::unique_ptr<Microtask>&& task)
63{
64 m_microtaskQueue.append(WTFMove(task));
65
66 m_timer.startOneShot(0_s);
67}
68
69void MicrotaskQueue::remove(const Microtask& task)
70{
71 for (size_t i = 0; i < m_microtaskQueue.size(); ++i) {
72 if (m_microtaskQueue[i].get() == &task) {
73 m_microtaskQueue.remove(i);
74 return;
75 }
76 }
77}
78
79void MicrotaskQueue::timerFired()
80{
81 performMicrotaskCheckpoint();
82}
83
84void MicrotaskQueue::performMicrotaskCheckpoint()
85{
86 if (m_performingMicrotaskCheckpoint)
87 return;
88
89 SetForScope<bool> change(m_performingMicrotaskCheckpoint, true);
90
91 Vector<std::unique_ptr<Microtask>> toKeep;
92 while (!m_microtaskQueue.isEmpty()) {
93 Vector<std::unique_ptr<Microtask>> queue = WTFMove(m_microtaskQueue);
94 for (auto& task : queue) {
95 auto result = task->run();
96 switch (result) {
97 case Microtask::Result::Done:
98 break;
99 case Microtask::Result::KeepInQueue:
100 toKeep.append(WTFMove(task));
101 break;
102 }
103 }
104 }
105
106 m_microtaskQueue = WTFMove(toKeep);
107}
108
109} // namespace WebCore
110