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:
PostTaskAndReplyRelay(const tracked_objects::Location & from_here,const Closure & task,const Closure & reply)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 
~PostTaskAndReplyRelay()36   ~PostTaskAndReplyRelay() {
37     DCHECK(origin_task_runner_->BelongsToCurrentThread());
38     task_.Reset();
39     reply_.Reset();
40   }
41 
Run()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:
RunReplyAndSelfDestruct()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 
PostTaskAndReply(const tracked_objects::Location & from_here,const Closure & task,const Closure & reply)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