blob: 841df96e5a68c5003305a3305c8ec87ac54a06da [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 "chrome/browser/policy/logging_work_scheduler.h"
#include <algorithm>
#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<base::Closure> 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<base::Closure> callback_;
};
EventLogger::Task::Task() {
}
EventLogger::Task::Task(int64 trigger_time,
int64 secondary_key,
linked_ptr<base::Closure> 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<base::Closure> 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<int64>* 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<int64>& events,
int64 start, int64 length) {
// The first interesting event.
std::vector<int64>::const_iterator begin_it =
std::lower_bound(events.begin(), events.end(), start);
// The event after the last interesting event.
std::vector<int64>::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