|  | // 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 <utility> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/debug/leak_annotations.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/sequenced_task_runner.h" | 
|  | #include "base/threading/sequenced_task_runner_handle.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class PostTaskAndReplyRelay { | 
|  | public: | 
|  | PostTaskAndReplyRelay(const Location& from_here, | 
|  | OnceClosure task, | 
|  | OnceClosure reply) | 
|  | : from_here_(from_here), | 
|  | task_(std::move(task)), | 
|  | reply_(std::move(reply)) {} | 
|  | PostTaskAndReplyRelay(PostTaskAndReplyRelay&&) = default; | 
|  |  | 
|  | ~PostTaskAndReplyRelay() { | 
|  | if (reply_) { | 
|  | // This can run: | 
|  | // 1) On origin sequence, when: | 
|  | //    1a) Posting |task_| fails. | 
|  | //    1b) |reply_| is cancelled before running. | 
|  | //    1c) The DeleteSoon() below is scheduled. | 
|  | // 2) On destination sequence, when: | 
|  | //    2a) |task_| is cancelled before running. | 
|  | //    2b) Posting |reply_| fails. | 
|  |  | 
|  | if (!reply_task_runner_->RunsTasksInCurrentSequence()) { | 
|  | // Case 2a) or 2b). | 
|  | // | 
|  | // Destroy callbacks asynchronously on |reply_task_runner| since their | 
|  | // destructors can rightfully be affine to it. As always, DeleteSoon() | 
|  | // might leak its argument if the target execution environment is | 
|  | // shutdown (e.g. MessageLoop deleted, TaskScheduler shutdown). | 
|  | // | 
|  | // Note: while it's obvious why |reply_| can be affine to | 
|  | // |reply_task_runner|, the reason that |task_| can also be affine to it | 
|  | // is that it if neither tasks ran, |task_| may still hold an object | 
|  | // which was intended to be moved to |reply_| when |task_| ran (such an | 
|  | // object's destruction can be affine to |reply_task_runner_| -- e.g. | 
|  | // https://crbug.com/829122). | 
|  | auto relay_to_delete = | 
|  | std::make_unique<PostTaskAndReplyRelay>(std::move(*this)); | 
|  | ANNOTATE_LEAKING_OBJECT_PTR(relay_to_delete.get()); | 
|  | reply_task_runner_->DeleteSoon(from_here_, std::move(relay_to_delete)); | 
|  | } | 
|  |  | 
|  | // Case 1a), 1b), 1c). | 
|  | // | 
|  | // Callbacks will be destroyed synchronously at the end of this scope. | 
|  | } else { | 
|  | // This can run when both callbacks have run or have been moved to another | 
|  | // PostTaskAndReplyRelay instance. If |reply_| is null, |task_| must be | 
|  | // null too. | 
|  | DCHECK(!task_); | 
|  | } | 
|  | } | 
|  |  | 
|  | // No assignment operator because of const members. | 
|  | PostTaskAndReplyRelay& operator=(PostTaskAndReplyRelay&&) = delete; | 
|  |  | 
|  | // Static function is used because it is not possible to bind a method call to | 
|  | // a non-pointer type. | 
|  | static void RunTaskAndPostReply(PostTaskAndReplyRelay relay) { | 
|  | DCHECK(relay.task_); | 
|  | std::move(relay.task_).Run(); | 
|  |  | 
|  | // Keep a reference to the reply TaskRunner for the PostTask() call before | 
|  | // |relay| is moved into a callback. | 
|  | scoped_refptr<SequencedTaskRunner> reply_task_runner = | 
|  | relay.reply_task_runner_; | 
|  |  | 
|  | reply_task_runner->PostTask( | 
|  | relay.from_here_, | 
|  | BindOnce(&PostTaskAndReplyRelay::RunReply, std::move(relay))); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Static function is used because it is not possible to bind a method call to | 
|  | // a non-pointer type. | 
|  | static void RunReply(PostTaskAndReplyRelay relay) { | 
|  | DCHECK(!relay.task_); | 
|  | DCHECK(relay.reply_); | 
|  | std::move(relay.reply_).Run(); | 
|  | } | 
|  |  | 
|  | const Location from_here_; | 
|  | OnceClosure task_; | 
|  | OnceClosure reply_; | 
|  | const scoped_refptr<SequencedTaskRunner> reply_task_runner_ = | 
|  | SequencedTaskRunnerHandle::Get(); | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(PostTaskAndReplyRelay); | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | bool PostTaskAndReplyImpl::PostTaskAndReply(const Location& from_here, | 
|  | OnceClosure task, | 
|  | OnceClosure reply) { | 
|  | DCHECK(task) << from_here.ToString(); | 
|  | DCHECK(reply) << from_here.ToString(); | 
|  |  | 
|  | return PostTask(from_here, | 
|  | BindOnce(&PostTaskAndReplyRelay::RunTaskAndPostReply, | 
|  | PostTaskAndReplyRelay(from_here, std::move(task), | 
|  | std::move(reply)))); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | }  // namespace base |