| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/threading/post_task_and_reply_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "base/message_loop_proxy.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| // This relay class remembers the MessageLoop that it was created on, and |
| // ensures that both the |task| and |reply| Closures are deleted on this same |
| // thread. Also, |task| is guaranteed to be deleted before |reply| is run or |
| // deleted. |
| // |
| // If this is not possible because the originating MessageLoop is no longer |
| // available, the the |task| and |reply| Closures are leaked. Leaking is |
| // considered preferable to having a thread-safetey violations caused by |
| // invoking the Closure destructor on the wrong thread. |
| class PostTaskAndReplyRelay { |
| public: |
| PostTaskAndReplyRelay(const tracked_objects::Location& from_here, |
| const Closure& task, const Closure& reply) |
| : from_here_(from_here), |
| origin_loop_(MessageLoopProxy::current()) { |
| task_ = task; |
| reply_ = reply; |
| } |
| |
| ~PostTaskAndReplyRelay() { |
| DCHECK(origin_loop_->BelongsToCurrentThread()); |
| task_.Reset(); |
| reply_.Reset(); |
| } |
| |
| void Run() { |
| task_.Run(); |
| origin_loop_->PostTask( |
| from_here_, |
| Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct, |
| base::Unretained(this))); |
| } |
| |
| private: |
| void RunReplyAndSelfDestruct() { |
| DCHECK(origin_loop_->BelongsToCurrentThread()); |
| |
| // Force |task_| to be released before |reply_| is to ensure that no one |
| // accidentally depends on |task_| keeping one of its arguments alive while |
| // |reply_| is executing. |
| task_.Reset(); |
| |
| reply_.Run(); |
| |
| // Cue mission impossible theme. |
| delete this; |
| } |
| |
| tracked_objects::Location from_here_; |
| scoped_refptr<MessageLoopProxy> origin_loop_; |
| Closure reply_; |
| Closure task_; |
| }; |
| |
| } // namespace |
| |
| namespace internal { |
| |
| bool PostTaskAndReplyImpl::PostTaskAndReply( |
| const tracked_objects::Location& from_here, |
| const Closure& task, |
| const Closure& reply) { |
| PostTaskAndReplyRelay* relay = |
| new PostTaskAndReplyRelay(from_here, task, reply); |
| if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run, |
| Unretained(relay)))) { |
| delete relay; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace internal |
| |
| } // namespace base |