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