• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/threading/post_task_and_reply_impl.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/logging.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/sequence_checker.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/threading/sequenced_task_runner_handle.h"
16 
17 namespace base {
18 
19 namespace {
20 
21 // This relay class remembers the sequence that it was created on, and ensures
22 // that both the |task| and |reply| Closures are deleted on this same sequence.
23 // Also, |task| is guaranteed to be deleted before |reply| is run or deleted.
24 //
25 // If RunReplyAndSelfDestruct() doesn't run because the originating execution
26 // context is no longer available, then the |task| and |reply| Closures are
27 // leaked. Leaking is considered preferable to having a thread-safetey
28 // violations caused by invoking the Closure destructor on the wrong sequence.
29 class PostTaskAndReplyRelay {
30  public:
PostTaskAndReplyRelay(const tracked_objects::Location & from_here,OnceClosure task,OnceClosure reply)31   PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
32                         OnceClosure task,
33                         OnceClosure reply)
34       : sequence_checker_(),
35         from_here_(from_here),
36         origin_task_runner_(SequencedTaskRunnerHandle::Get()),
37         reply_(std::move(reply)),
38         task_(std::move(task)) {}
39 
~PostTaskAndReplyRelay()40   ~PostTaskAndReplyRelay() {
41     DCHECK(sequence_checker_.CalledOnValidSequence());
42   }
43 
RunTaskAndPostReply()44   void RunTaskAndPostReply() {
45     std::move(task_).Run();
46     origin_task_runner_->PostTask(
47         from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
48                          base::Unretained(this)));
49   }
50 
51  private:
RunReplyAndSelfDestruct()52   void RunReplyAndSelfDestruct() {
53     DCHECK(sequence_checker_.CalledOnValidSequence());
54 
55     // Ensure |task_| has already been released before |reply_| to ensure that
56     // no one accidentally depends on |task_| keeping one of its arguments alive
57     // while |reply_| is executing.
58     DCHECK(!task_);
59 
60     std::move(reply_).Run();
61 
62     // Cue mission impossible theme.
63     delete this;
64   }
65 
66   const SequenceChecker sequence_checker_;
67   const tracked_objects::Location from_here_;
68   const scoped_refptr<SequencedTaskRunner> origin_task_runner_;
69   OnceClosure reply_;
70   OnceClosure task_;
71 };
72 
73 }  // namespace
74 
75 namespace internal {
76 
PostTaskAndReply(const tracked_objects::Location & from_here,OnceClosure task,OnceClosure reply)77 bool PostTaskAndReplyImpl::PostTaskAndReply(
78     const tracked_objects::Location& from_here,
79     OnceClosure task,
80     OnceClosure reply) {
81   DCHECK(!task.is_null()) << from_here.ToString();
82   DCHECK(!reply.is_null()) << from_here.ToString();
83   PostTaskAndReplyRelay* relay =
84       new PostTaskAndReplyRelay(from_here, std::move(task), std::move(reply));
85   // PostTaskAndReplyRelay self-destructs after executing |reply|. On the flip
86   // side though, it is intentionally leaked if the |task| doesn't complete
87   // before the origin sequence stops executing tasks. Annotate |relay| as leaky
88   // to avoid having to suppress every callsite which happens to flakily trigger
89   // this race.
90   ANNOTATE_LEAKING_OBJECT_PTR(relay);
91   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::RunTaskAndPostReply,
92                                 Unretained(relay)))) {
93     delete relay;
94     return false;
95   }
96 
97   return true;
98 }
99 
100 }  // namespace internal
101 
102 }  // namespace base
103