1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
content / services / auction_worklet / debug_command_queue.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/services/auction_worklet/debug_command_queue.h"
#include "base/containers/contains.h"
#include "base/task/sequenced_task_runner.h"
namespace auction_worklet {
DebugCommandQueue::DebugCommandQueue(
scoped_refptr<base::SequencedTaskRunner> v8_runner)
: v8_runner_(std::move(v8_runner)), wake_up_(&lock_) {}
DebugCommandQueue::~DebugCommandQueue() = default;
void DebugCommandQueue::PauseForDebuggerAndRunCommands(
int context_group_id,
base::OnceClosure abort_helper) {
DCHECK(v8_runner_->RunsTasksInCurrentSequence());
DCHECK(abort_helper);
base::AutoLock auto_lock(lock_);
CHECK(!v8_thread_paused_);
DCHECK(!pause_abort_helper_);
if (base::Contains(aborted_context_group_ids_, context_group_id)) {
// Pauses disallowed since worklet is in process of being destroyed
return;
}
v8_thread_paused_ = true;
paused_context_group_id_ = context_group_id;
pause_abort_helper_ = std::move(abort_helper);
while (true) {
RunQueueWithLockHeld();
if (v8_thread_paused_)
wake_up_.Wait();
else
break;
}
pause_abort_helper_.Reset();
}
void DebugCommandQueue::AbortPauses(int context_group_id) {
base::AutoLock auto_lock(lock_);
aborted_context_group_ids_.insert(context_group_id);
if (v8_thread_paused_ && paused_context_group_id_ == context_group_id) {
DCHECK(pause_abort_helper_);
queue_.push(std::move(pause_abort_helper_));
wake_up_.Signal();
}
}
void DebugCommandQueue::RecycleContextGroupId(int context_group_id) {
base::AutoLock auto_lock(lock_);
size_t num_erased = aborted_context_group_ids_.erase(context_group_id);
DCHECK_EQ(num_erased, 1u)
<< "DebugId::AbortDebuggerPauses must be called before ~DebugId.";
}
void DebugCommandQueue::QuitPauseForDebugger() {
// Can be called from any thread.
base::AutoLock auto_lock(lock_);
v8_thread_paused_ = false;
wake_up_.Signal();
}
void DebugCommandQueue::QueueTaskForV8Thread(base::OnceClosure task) {
DCHECK(task);
// Can be called from any thread.
base::AutoLock auto_lock(lock_);
queue_.push(std::move(task));
if (v8_thread_paused_) {
wake_up_.Signal();
} else {
PostRunQueue();
}
}
void DebugCommandQueue::PostRunQueue() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
if (!queue_.empty()) {
v8_runner_->PostTask(FROM_HERE,
base::BindOnce(&DebugCommandQueue::RunQueue, this));
}
}
void DebugCommandQueue::RunQueue() {
DCHECK(v8_runner_->RunsTasksInCurrentSequence());
// Note: one of commands in the queue can cause PauseForDebuggerAndRunCommands
// to be entered. This is OK since we pull tasks off one-by-one and run them
// w/o a lock held.
base::AutoLock auto_lock(lock_);
RunQueueWithLockHeld();
}
void DebugCommandQueue::RunQueueWithLockHeld() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
DCHECK(v8_runner_->RunsTasksInCurrentSequence());
bool was_v8_thread_paused_ = v8_thread_paused_;
while (!queue_.empty()) {
base::OnceClosure to_run = std::move(queue_.front());
queue_.pop();
{
// Relinquish lock for running callback.
base::AutoUnlock temporary_unlock(lock_);
std::move(to_run).Run();
}
// Need to re-asses state here since it may have changed while lock was
// released.
if (was_v8_thread_paused_ && !v8_thread_paused_) {
// QuitPauseForDebugger() was called, do the rest at top-level.
PostRunQueue();
return;
}
}
}
} // namespace auction_worklet