blob: c906866cfb8e61143279a833ed4f5ea04971fb07 [file] [log] [blame]
// 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/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.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 {
PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply)
: from_here_(from_here),
origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
task_ = task;
reply_ = reply;
~PostTaskAndReplyRelay() {
void Run() {
from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
void RunReplyAndSelfDestruct() {
// 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.
// Cue mission impossible theme.
delete this;
tracked_objects::Location from_here_;
scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
Closure reply_;
Closure task_;
} // namespace
namespace internal {
bool PostTaskAndReplyImpl::PostTaskAndReply(
const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply) {
// TODO(tzik): Use DCHECK here once the crash is gone.
CHECK(!task.is_null()) << from_here.ToString();
CHECK(!reply.is_null()) << from_here.ToString();
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