15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/task/cancelable_task_tracker.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
10424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/callback_helpers.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/location.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/cancellation_flag.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/task_runner.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Bind;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::CancellationFlag;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Closure;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::hash_map;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TaskRunner;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RunIfNotCanceled(const CancellationFlag* flag, const Closure& task) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!flag->IsSet())
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    task.Run();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RunIfNotCanceledThenUntrack(const CancellationFlag* flag,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const Closure& task,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const Closure& untrack) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunIfNotCanceled(flag, task);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  untrack.Run();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool IsCanceled(const CancellationFlag* flag,
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                base::ScopedClosureRunner* cleanup_runner) {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return flag->IsSet();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RunAndDeleteFlag(const Closure& closure, const CancellationFlag* flag) {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closure.Run();
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete flag;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RunOrPostToTaskRunner(TaskRunner* task_runner, const Closure& closure) {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (task_runner->RunsTasksOnCurrentThread())
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    closure.Run();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    task_runner->PostTask(FROM_HERE, closure);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace base {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableTaskTracker::CancelableTaskTracker()
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : next_id_(1),weak_factory_(this) {}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableTaskTracker::~CancelableTaskTracker() {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TryCancelAll();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TaskRunner* task_runner,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Closure& task) {
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PostTaskAndReply(task_runner, from_here, task, Bind(&base::DoNothing));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TaskRunner* task_runner,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& from_here,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Closure& task,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Closure& reply) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need a MessageLoop to run reply.
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(base::MessageLoopProxy::current().get());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Owned by reply callback below.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CancellationFlag* flag = new CancellationFlag();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TaskId id = next_id_;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_id_++;  // int64 is big enough that we ignore the potential overflow.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Closure& untrack_closure =
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool success =
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      task_runner->PostTaskAndReply(from_here,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    Bind(&RunIfNotCanceled, flag, task),
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    Bind(&RunIfNotCanceledThenUntrack,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         base::Owned(flag),
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         reply,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         untrack_closure));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kBadTaskId;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Track(id, flag);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    IsCanceledCallback* is_canceled_cb) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  DCHECK(base::MessageLoopProxy::current().get());
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TaskId id = next_id_;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  next_id_++;  // int64 is big enough that we ignore the potential overflow.
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Will be deleted by |untrack_and_delete_flag| after Untrack().
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CancellationFlag* flag = new CancellationFlag();
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Closure untrack_and_delete_flag = Bind(
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &RunAndDeleteFlag,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      flag);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Will always run |untrack_and_delete_flag| on current MessageLoop.
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ScopedClosureRunner* untrack_and_delete_flag_runner =
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         base::MessageLoopProxy::current(),
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                         untrack_and_delete_flag));
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *is_canceled_cb =
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Bind(&IsCanceled, flag, base::Owned(untrack_and_delete_flag_runner));
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Track(id, flag);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return id;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CancelableTaskTracker::TryCancel(TaskId id) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash_map<TaskId, CancellationFlag*>::const_iterator it = task_flags_.find(id);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (it == task_flags_.end()) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Two possibilities:
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //   1. The task has already been untracked.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //   2. The TaskId is bad or unknown.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Since this function is best-effort, it's OK to ignore these.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  it->second->Set();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CancelableTaskTracker::TryCancelAll() {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (hash_map<TaskId, CancellationFlag*>::const_iterator it =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           task_flags_.begin();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != task_flags_.end();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    it->second->Set();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool CancelableTaskTracker::HasTrackedTasks() const {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !task_flags_.empty();
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = task_flags_.insert(std::make_pair(id, flag)).second;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(success);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CancelableTaskTracker::Untrack(TaskId id) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num = task_flags_.erase(id);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(1u, num);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace base
188