diff options
author | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-18 23:13:01 +0000 |
---|---|---|
committer | ajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-18 23:13:01 +0000 |
commit | c31af70db21e370eee35a677f6fcc62a2963784a (patch) | |
tree | b3f1908471efc10ac35d61cbffa2c7d160d6247f /base/message_loop_proxy.cc | |
parent | d55c2380d728c2cc29c1a84970bb1d6f51c397d7 (diff) | |
download | chromium_src-c31af70db21e370eee35a677f6fcc62a2963784a.zip chromium_src-c31af70db21e370eee35a677f6fcc62a2963784a.tar.gz chromium_src-c31af70db21e370eee35a677f6fcc62a2963784a.tar.bz2 |
Implementation of PostTaskAndReply() in MessageLoopProxy and BrowserThread.
This ensures that the request/reply closures are always deleted on the origin
thread, or leaked if the task cannot be completed (due to message loop
shutdown).
BUG=86301
TEST=new unittests
Review URL: http://codereview.chromium.org/7210053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97387 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_loop_proxy.cc')
-rw-r--r-- | base/message_loop_proxy.cc | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/base/message_loop_proxy.cc b/base/message_loop_proxy.cc index a38db39..7433e25 100644 --- a/base/message_loop_proxy.cc +++ b/base/message_loop_proxy.cc @@ -1,17 +1,92 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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/message_loop_proxy.h" +#include "base/bind.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 + MessageLoopProxy::MessageLoopProxy() { } MessageLoopProxy::~MessageLoopProxy() { } +bool MessageLoopProxy::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; +} + void MessageLoopProxy::OnDestruct() const { delete this; } |