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 "base/bind.h"
      8 #include "base/location.h"
      9 #include "base/single_thread_task_runner.h"
     10 #include "base/thread_task_runner_handle.h"
     11 
     12 namespace base {
     13 
     14 namespace {
     15 
     16 // This relay class remembers the MessageLoop that it was created on, and
     17 // ensures that both the |task| and |reply| Closures are deleted on this same
     18 // thread. Also, |task| is guaranteed to be deleted before |reply| is run or
     19 // deleted.
     20 //
     21 // If this is not possible because the originating MessageLoop is no longer
     22 // available, the the |task| and |reply| Closures are leaked.  Leaking is
     23 // considered preferable to having a thread-safetey violations caused by
     24 // invoking the Closure destructor on the wrong thread.
     25 class PostTaskAndReplyRelay {
     26  public:
     27   PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
     28                         const Closure& task, const Closure& reply)
     29       : from_here_(from_here),
     30         origin_loop_(ThreadTaskRunnerHandle::Get()) {
     31     task_ = task;
     32     reply_ = reply;
     33   }
     34 
     35   ~PostTaskAndReplyRelay() {
     36     DCHECK(origin_loop_->BelongsToCurrentThread());
     37     task_.Reset();
     38     reply_.Reset();
     39   }
     40 
     41   void Run() {
     42     task_.Run();
     43     origin_loop_->PostTask(
     44         from_here_,
     45         Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
     46              base::Unretained(this)));
     47   }
     48 
     49  private:
     50   void RunReplyAndSelfDestruct() {
     51     DCHECK(origin_loop_->BelongsToCurrentThread());
     52 
     53     // Force |task_| to be released before |reply_| is to ensure that no one
     54     // accidentally depends on |task_| keeping one of its arguments alive while
     55     // |reply_| is executing.
     56     task_.Reset();
     57 
     58     reply_.Run();
     59 
     60     // Cue mission impossible theme.
     61     delete this;
     62   }
     63 
     64   tracked_objects::Location from_here_;
     65   scoped_refptr<SingleThreadTaskRunner> origin_loop_;
     66   Closure reply_;
     67   Closure task_;
     68 };
     69 
     70 }  // namespace
     71 
     72 namespace internal {
     73 
     74 bool PostTaskAndReplyImpl::PostTaskAndReply(
     75     const tracked_objects::Location& from_here,
     76     const Closure& task,
     77     const Closure& reply) {
     78   PostTaskAndReplyRelay* relay =
     79       new PostTaskAndReplyRelay(from_here, task, reply);
     80   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
     81                                 Unretained(relay)))) {
     82     delete relay;
     83     return false;
     84   }
     85 
     86   return true;
     87 }
     88 
     89 }  // namespace internal
     90 
     91 }  // namespace base
     92