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,
     29                         const Closure& reply)
     30       : from_here_(from_here),
     31         origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
     32     task_ = task;
     33     reply_ = reply;
     34   }
     35 
     36   ~PostTaskAndReplyRelay() {
     37     DCHECK(origin_task_runner_->BelongsToCurrentThread());
     38     task_.Reset();
     39     reply_.Reset();
     40   }
     41 
     42   void Run() {
     43     task_.Run();
     44     origin_task_runner_->PostTask(
     45         from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
     46                          base::Unretained(this)));
     47   }
     48 
     49  private:
     50   void RunReplyAndSelfDestruct() {
     51     DCHECK(origin_task_runner_->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_task_runner_;
     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   // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
     79   CHECK(!task.is_null()) << from_here.ToString();
     80   CHECK(!reply.is_null()) << from_here.ToString();
     81   PostTaskAndReplyRelay* relay =
     82       new PostTaskAndReplyRelay(from_here, task, reply);
     83   if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
     84                                 Unretained(relay)))) {
     85     delete relay;
     86     return false;
     87   }
     88 
     89   return true;
     90 }
     91 
     92 }  // namespace internal
     93 
     94 }  // namespace base
     95