Home | History | Annotate | Download | only in threading
      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:
     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 
     40   ~PostTaskAndReplyRelay() {
     41     DCHECK(sequence_checker_.CalledOnValidSequence());
     42   }
     43 
     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:
     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 
     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