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