| Index: base/message_loop_proxy.cc
|
| diff --git a/base/message_loop_proxy.cc b/base/message_loop_proxy.cc
|
| index a38db393f6e4aa63412455d435804b608f86c682..7433e258e50473608f3fd87d25bd4508718c6930 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;
|
| }
|
|
|