// 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 "chrome/browser/policy/logging_work_scheduler.h" #include #include "base/bind.h" #include "base/message_loop.h" #include "content/public/browser/browser_thread.h" using content::BrowserThread; namespace policy { // Objects of this class are used in the priority-queue of future tasks // in EventLogger. class EventLogger::Task { public: Task(); Task(int64 trigger_time, int64 secondary_key, linked_ptr callback); ~Task(); // Returns true if |this| should be executed before |rhs|. // Used for sorting by the priority queue. bool operator< (const Task& rhs) const; int64 trigger_time() const; // Returns a copy of the callback object of this task, and resets the // original callback object. (LoggingTaskScheduler owns a linked_ptr to // its task's callback objects and it only allows firing new tasks if the // previous task's callback object has been reset.) base::Closure GetAndResetCallback(); private: // The virtual time when this task will trigger. // Smaller times win. int64 trigger_time_; // Used for sorting tasks that have the same trigger_time. // Bigger keys win. int64 secondary_key_; linked_ptr callback_; }; EventLogger::Task::Task() { } EventLogger::Task::Task(int64 trigger_time, int64 secondary_key, linked_ptr callback) : trigger_time_(trigger_time), secondary_key_(secondary_key), callback_(callback) { } EventLogger::Task::~Task() { } bool EventLogger::Task::operator< (const Task& rhs) const { if (trigger_time_ == rhs.trigger_time_) { return secondary_key_ < rhs.secondary_key_; } else { return trigger_time_ > rhs.trigger_time_; } } int64 EventLogger::Task::trigger_time() const { return trigger_time_; } base::Closure EventLogger::Task::GetAndResetCallback() { // Make a copy. base::Closure callback = *(callback_.get()); // Reset the original callback, which is shared with LoggingTaskScheduler. callback_->Reset(); return callback; } EventLogger::EventLogger() : step_pending_(false), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), current_time_(0), task_counter_(0) { } EventLogger::~EventLogger() { } void EventLogger::PostDelayedWork( linked_ptr callback, int64 delay) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); int64 trigger_time = current_time_ + delay; task_counter_++; scheduled_tasks_.push(Task(trigger_time, task_counter_, callback)); if (!step_pending_) { step_pending_ = true; MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&EventLogger::Step, weak_ptr_factory_.GetWeakPtr())); } } void EventLogger::RegisterEvent() { events_.push_back(current_time_); } void EventLogger::Swap(std::vector* events) { std::swap(events_, *events); } // static // Counts the number of elements in a sorted integer vector that are // >= |start| but < |start| + |length|. int EventLogger::CountEvents(const std::vector& events, int64 start, int64 length) { // The first interesting event. std::vector::const_iterator begin_it = std::lower_bound(events.begin(), events.end(), start); // The event after the last interesting event. std::vector::const_iterator end_it = std::lower_bound(begin_it, events.end(), start + length); return end_it - begin_it; } void EventLogger::Step() { DCHECK(step_pending_); step_pending_ = false; if (scheduled_tasks_.empty()) return; // Take the next scheduled task from the queue. Task next = scheduled_tasks_.top(); scheduled_tasks_.pop(); base::Closure callback = next.GetAndResetCallback(); int64 trigger_time = next.trigger_time(); DCHECK(trigger_time >= current_time_); // Execute the next scheduled task if it was not cancelled. if (!callback.is_null()) { current_time_ = trigger_time; callback.Run(); // Note: new items may be added to scheduled_tasks_ here. } // Trigger calling this method if there are remaining tasks. if (!step_pending_ && !scheduled_tasks_.empty()) { step_pending_ = true; MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&EventLogger::Step, weak_ptr_factory_.GetWeakPtr())); } } DummyWorkScheduler::DummyWorkScheduler() { } DummyWorkScheduler::~DummyWorkScheduler() { CancelDelayedWork(); } void DummyWorkScheduler::PostDelayedWork( const base::Closure& callback, int64 delay) { DelayedWorkScheduler::PostDelayedWork(callback, 0); } LoggingWorkScheduler::LoggingWorkScheduler(EventLogger* logger) : logger_(logger) { } LoggingWorkScheduler::~LoggingWorkScheduler() { if (callback_.get()) callback_->Reset(); } void LoggingWorkScheduler::PostDelayedWork( const base::Closure& callback, int64 delay) { DCHECK(!callback_.get() || callback_->is_null()); callback_.reset(new base::Closure(callback)); logger_->PostDelayedWork(callback_, delay); } void LoggingWorkScheduler::CancelDelayedWork() { if (!callback_.get()) return; callback_->Reset(); // Erase the callback to the delayed work. callback_.reset(NULL); // Erase the pointer to the callback. } } // namespace policy