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
12namespace base {
13
14namespace {
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.
25class 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
72namespace internal {
73
74bool 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