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
base / threading / post_task_and_reply_impl.cc [blame]
// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/threading/post_task_and_reply_impl.h"
#include <utility>
#include "base/check_op.h"
#include "base/debug/leak_annotations.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool/thread_pool_instance.h"
namespace base::internal {
PostTaskAndReplyRelay::PostTaskAndReplyRelay(
const Location& from_here,
OnceClosure task,
OnceClosure reply,
scoped_refptr<SequencedTaskRunner> reply_task_runner)
: from_here_(from_here),
task_(std::move(task)),
reply_(std::move(reply)),
reply_task_runner_(std::move(reply_task_runner)) {}
PostTaskAndReplyRelay::PostTaskAndReplyRelay(PostTaskAndReplyRelay&&) = default;
// It is important that `reply_` always be deleted on the origin sequence
// (`reply_task_runner_`) since its destructor can be affine to it. More
// sutbly, it is also important that `task_` be destroyed on the origin
// sequence when it fails to run. This is because `task_` can own state which
// is affine to `reply_task_runner_` and was intended to be handed to
// `reply_`, e.g. https://crbug.com/829122. Since `task_` already needs to
// support deletion on the origin sequence (since the initial PostTask can
// always fail), it's safer to delete it there when PostTask succeeds but
// `task_` is later prevented from running.
//
// PostTaskAndReplyRelay's move semantics along with logic in this destructor
// enforce the above semantics in all the following cases :
// 1) Posting `task_` fails right away on the origin sequence:
// a) `reply_task_runner_` is null (i.e. during late shutdown);
// b) `reply_task_runner_` is set.
// 2) ~PostTaskAndReplyRelay() runs on the destination sequence:
// a) RunTaskAndPostReply() is cancelled before running;
// b) RunTaskAndPostReply() is skipped on shutdown;
// c) Posting RunReply() fails.
// 3) ~PostTaskAndReplyRelay() runs on the origin sequence:
// a) RunReply() is cancelled before running;
// b) RunReply() is skipped on shutdown;
// c) The DeleteSoon() posted by (2) runs.
// 4) ~PostTaskAndReplyRelay() should no-op:
// a) This relay was moved to another relay instance;
// b) RunReply() ran and completed this relay's mandate.
PostTaskAndReplyRelay::~PostTaskAndReplyRelay() {
// Case 1a and 4a:
if (!reply_task_runner_) {
DCHECK_EQ(task_.is_null(), reply_.is_null());
return;
}
// Case 4b:
if (!reply_) {
DCHECK(!task_);
return;
}
// Case 2:
if (!reply_task_runner_->RunsTasksInCurrentSequence()) {
DCHECK(reply_);
// Allow this task to be leaked on shutdown even if `reply_task_runner_`
// has the TaskShutdownBehaviour::BLOCK_SHUTDOWN trait. Without `fizzler`,
// such a task runner would DCHECK when posting to `reply_task_runner_`
// after shutdown. Ignore this DCHECK as the poster isn't in control when
// its Callback is destroyed late into shutdown. Ref. crbug.com/1375270.
base::ThreadPoolInstance::ScopedFizzleBlockShutdownTasks fizzler;
SequencedTaskRunner* reply_task_runner_raw = reply_task_runner_.get();
auto relay_to_delete =
std::make_unique<PostTaskAndReplyRelay>(std::move(*this));
// In case 2c, posting the DeleteSoon will also fail and `relay_to_delete`
// will be leaked. This only happens during shutdown and leaking is better
// than thread-unsafe execution.
ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get());
reply_task_runner_raw->DeleteSoon(from_here_, std::move(relay_to_delete));
return;
}
// Case 1b and 3: Any remaining state will be destroyed synchronously at the
// end of this scope.
}
} // namespace base::internal