summaryrefslogtreecommitdiffstats
path: root/base/message_loop_proxy.cc
diff options
context:
space:
mode:
authorajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-18 23:13:01 +0000
committerajwong@chromium.org <ajwong@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-18 23:13:01 +0000
commitc31af70db21e370eee35a677f6fcc62a2963784a (patch)
treeb3f1908471efc10ac35d61cbffa2c7d160d6247f /base/message_loop_proxy.cc
parentd55c2380d728c2cc29c1a84970bb1d6f51c397d7 (diff)
downloadchromium_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.cc77
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;
}