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