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