// Copyright (c) 2012 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 "net/quic/quic_chromium_alarm_factory.h" #include "base/bind.h" #include "base/location.h" #include "base/logging.h" #include "base/metrics/sparse_histogram.h" #include "base/task_runner.h" #include "base/time/time.h" namespace net { namespace { class QuicChromeAlarm : public quic::QuicAlarm { public: QuicChromeAlarm(const quic::QuicClock* clock, base::TaskRunner* task_runner, quic::QuicArenaScopedPtr delegate) : quic::QuicAlarm(std::move(delegate)), clock_(clock), task_runner_(task_runner), task_deadline_(quic::QuicTime::Zero()), weak_factory_(this) {} protected: void SetImpl() override { DCHECK(deadline().IsInitialized()); if (task_deadline_.IsInitialized()) { if (task_deadline_ <= deadline()) { // Since tasks can not be un-posted, OnAlarm will be invoked which // will notice that deadline has not yet been reached, and will set // the alarm for the new deadline. return; } // The scheduled task is after new deadline. Invalidate the weak ptrs // so that task does not execute when we're not expecting it. weak_factory_.InvalidateWeakPtrs(); } int64_t delay_us = (deadline() - (clock_->Now())).ToMicroseconds(); if (delay_us < 0) { delay_us = 0; } task_runner_->PostDelayedTask( FROM_HERE, base::Bind(&QuicChromeAlarm::OnAlarm, weak_factory_.GetWeakPtr()), base::TimeDelta::FromMicroseconds(delay_us)); task_deadline_ = deadline(); } void CancelImpl() override { DCHECK(!deadline().IsInitialized()); // Since tasks can not be un-posted, OnAlarm will be invoked which // will notice that deadline is not Initialized and will do nothing. } private: void OnAlarm() { DCHECK(task_deadline_.IsInitialized()); task_deadline_ = quic::QuicTime::Zero(); // The alarm may have been cancelled. if (!deadline().IsInitialized()) { return; } // The alarm may have been re-set to a later time. if (clock_->Now() < deadline()) { SetImpl(); return; } Fire(); } const quic::QuicClock* clock_; base::TaskRunner* task_runner_; // If a task has been posted to the message loop, this is the time it // was scheduled to fire. Tracking this allows us to avoid posting a // new tast if the new deadline is in the future, but permits us to // post a new task when the new deadline now earlier than when // previously posted. quic::QuicTime task_deadline_; base::WeakPtrFactory weak_factory_; }; } // namespace QuicChromiumAlarmFactory::QuicChromiumAlarmFactory( base::TaskRunner* task_runner, const quic::QuicClock* clock) : task_runner_(task_runner), clock_(clock), weak_factory_(this) {} QuicChromiumAlarmFactory::~QuicChromiumAlarmFactory() {} quic::QuicArenaScopedPtr QuicChromiumAlarmFactory::CreateAlarm( quic::QuicArenaScopedPtr delegate, quic::QuicConnectionArena* arena) { if (arena != nullptr) { return arena->New(clock_, task_runner_, std::move(delegate)); } else { return quic::QuicArenaScopedPtr( new QuicChromeAlarm(clock_, task_runner_, std::move(delegate))); } } quic::QuicAlarm* QuicChromiumAlarmFactory::CreateAlarm( quic::QuicAlarm::Delegate* delegate) { return new QuicChromeAlarm( clock_, task_runner_, quic::QuicArenaScopedPtr(delegate)); } } // namespace net