summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/timer.cc181
-rw-r--r--base/timer.h292
-rw-r--r--base/timer_unittest.cc123
-rw-r--r--chrome/browser/profiles/profile_impl.cc2
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc8
-rw-r--r--content/browser/download/download_file_manager.cc14
-rw-r--r--content/browser/download/download_file_manager.h2
-rw-r--r--content/browser/in_process_webkit/webkit_thread.cc6
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host_impl.cc13
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host_impl.h3
-rw-r--r--content/common/net/url_fetcher_impl.cc8
-rw-r--r--media/audio/audio_input_controller.cc16
-rw-r--r--media/audio/audio_input_controller.h4
-rw-r--r--net/disk_cache/backend_impl.cc7
-rw-r--r--net/disk_cache/backend_impl.h2
-rw-r--r--ui/aura/gestures/gesture_recognizer_unittest.cc6
16 files changed, 469 insertions, 218 deletions
diff --git a/base/timer.cc b/base/timer.cc
index 5c2aa21..e51660c 100644
--- a/base/timer.cc
+++ b/base/timer.cc
@@ -4,28 +4,181 @@
#include "base/timer.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
+#include "base/logging.h"
#include "base/message_loop.h"
namespace base {
-void BaseTimer_Helper::OrphanDelayedTask() {
- if (delayed_task_) {
- delayed_task_->timer_ = NULL;
- delayed_task_ = NULL;
+// BaseTimerTaskInternal is a simple delegate for scheduling a callback to
+// Timer in the MessageLoop. It also handles the following edge
+// cases:
+// - deleted by MessageLoop.
+// - abandoned (orphaned) by Timer.
+class BaseTimerTaskInternal {
+ public:
+ BaseTimerTaskInternal(Timer* timer)
+ : timer_(timer) {
}
+
+ ~BaseTimerTaskInternal() {
+ // This task may be getting cleared because the MessageLoop has been
+ // destructed. If so, don't leave Timer with a dangling pointer
+ // to this.
+ if (timer_)
+ timer_->StopAndAbandon();
+ }
+
+ void Run() {
+ // timer_ is NULL if we were abandoned.
+ if (!timer_)
+ return;
+
+ // *this will be deleted by the MessageLoop, so Timer needs to
+ // forget us:
+ timer_->scheduled_task_ = NULL;
+
+ // Although Timer should not call back into *this, let's clear
+ // the timer_ member first to be pedantic.
+ Timer* timer = timer_;
+ timer_ = NULL;
+ timer->RunScheduledTask();
+ }
+
+ // The task remains in the MessageLoop queue, but nothing will happen when it
+ // runs.
+ void Abandon() {
+ timer_ = NULL;
+ }
+
+ private:
+ Timer* timer_;
+};
+
+Timer::Timer(bool retain_user_task, bool is_repeating)
+ : scheduled_task_(NULL),
+ thread_id_(0),
+ is_repeating_(is_repeating),
+ retain_user_task_(retain_user_task),
+ is_running_(false) {
+}
+
+Timer::Timer(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task,
+ bool is_repeating)
+ : scheduled_task_(NULL),
+ posted_from_(posted_from),
+ delay_(delay),
+ user_task_(user_task),
+ thread_id_(0),
+ is_repeating_(is_repeating),
+ retain_user_task_(true),
+ is_running_(false) {
+}
+
+Timer::~Timer() {
+ StopAndAbandon();
+}
+
+void Timer::Start(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task) {
+ SetTaskInfo(posted_from, delay, user_task);
+ Reset();
+}
+
+void Timer::Stop() {
+ is_running_ = false;
+ if (!retain_user_task_)
+ user_task_.Reset();
+}
+
+void Timer::Reset() {
+ DCHECK(!user_task_.is_null());
+
+ // If there's no pending task, start one up and return.
+ if (!scheduled_task_) {
+ PostNewScheduledTask(delay_);
+ return;
+ }
+
+ // Set the new desired_run_time_.
+ desired_run_time_ = TimeTicks::Now() + delay_;
+
+ // We can use the existing scheduled task if it arrives before the new
+ // desired_run_time_.
+ if (desired_run_time_ > scheduled_run_time_) {
+ is_running_ = true;
+ return;
+ }
+
+ // We can't reuse the scheduled_task_, so abandon it and post a new one.
+ AbandonScheduledTask();
+ PostNewScheduledTask(delay_);
}
-void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) {
- OrphanDelayedTask();
+void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task) {
+ posted_from_ = posted_from;
+ delay_ = delay;
+ user_task_ = user_task;
+}
+
+void Timer::PostNewScheduledTask(TimeDelta delay) {
+ DCHECK(scheduled_task_ == NULL);
+ is_running_ = true;
+ scheduled_task_ = new BaseTimerTaskInternal(this);
+ MessageLoop::current()->PostDelayedTask(posted_from_,
+ base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
+ delay);
+ scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
+ // Remember the thread ID that posts the first task -- this will be verified
+ // later when the task is abandoned to detect misuse from multiple threads.
+ if (!thread_id_)
+ thread_id_ = static_cast<int>(PlatformThread::CurrentId());
+}
+
+void Timer::AbandonScheduledTask() {
+ DCHECK(thread_id_ == 0 ||
+ thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
+ if (scheduled_task_) {
+ scheduled_task_->Abandon();
+ scheduled_task_ = NULL;
+ }
+}
+
+void Timer::RunScheduledTask() {
+ // Task may have been disabled.
+ if (!is_running_)
+ return;
+
+ // First check if we need to delay the task because of a new target time.
+ if (desired_run_time_ > scheduled_run_time_) {
+ // TimeTicks::Now() can be expensive, so only call it if we know the user
+ // has changed the desired_run_time_.
+ TimeTicks now = TimeTicks::Now();
+ // MessageLoop may have called us late anyway, so only post a continuation
+ // task if the desired_run_time_ is in the future.
+ if (desired_run_time_ > now) {
+ // Post a new task to span the remaining time.
+ PostNewScheduledTask(desired_run_time_ - now);
+ return;
+ }
+ }
+
+ // Make a local copy of the task to run. The Stop method will reset the
+ // user_task_ member if retain_user_task_ is false.
+ base::Closure task = user_task_;
+
+ if (is_repeating_)
+ PostNewScheduledTask(delay_);
+ else
+ Stop();
+
+ task.Run();
- delayed_task_ = timer_task;
- delayed_task_->timer_ = this;
- MessageLoop::current()->PostDelayedTask(
- timer_task->posted_from_,
- base::Bind(&TimerTask::Run, base::Owned(timer_task)),
- timer_task->delay_);
+ // No more member accesses here: *this could be deleted at this point.
}
} // namespace base
diff --git a/base/timer.h b/base/timer.h
index 9c9bec7..24f2bb1 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -38,6 +38,8 @@
// calling Reset on timer_ would postpone DoStuff by another 1 second. In
// other words, Reset is shorthand for calling Stop and then Start again with
// the same arguments.
+//
+// NOTE: These APIs are not thread safe. Always call from the same thread.
#ifndef BASE_TIMER_H_
#define BASE_TIMER_H_
@@ -49,174 +51,162 @@
// should be able to tell the difference.
#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
#include "base/location.h"
-#include "base/logging.h"
#include "base/time.h"
class MessageLoop;
namespace base {
+class BaseTimerTaskInternal;
+
//-----------------------------------------------------------------------------
-// This class is an implementation detail of OneShotTimer and RepeatingTimer.
-// Please do not use this class directly.
+// This class wraps MessageLoop::PostDelayedTask to manage delayed and repeating
+// tasks. It must be destructed on the same thread that starts tasks. There are
+// DCHECKs in place to verify this.
//
-// This class exists to share code between BaseTimer<T> template instantiations.
-//
-class BASE_EXPORT BaseTimer_Helper {
+class BASE_EXPORT Timer {
public:
- // Stops the timer.
- ~BaseTimer_Helper() {
- OrphanDelayedTask();
- }
+ // Construct a timer in repeating or one-shot mode. Start or SetTaskInfo must
+ // be called later to set task info. |retain_user_task| determines whether the
+ // user_task is retained or reset when it runs or stops.
+ Timer(bool retain_user_task, bool is_repeating);
+
+ // Construct a timer with retained task info.
+ Timer(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task,
+ bool is_repeating);
+
+ virtual ~Timer();
// Returns true if the timer is running (i.e., not stopped).
bool IsRunning() const {
- return delayed_task_ != NULL;
+ return is_running_;
}
- // Returns the current delay for this timer. May only call this method when
- // the timer is running!
+ // Returns the current delay for this timer.
TimeDelta GetCurrentDelay() const {
- DCHECK(IsRunning());
- return delayed_task_->delay_;
+ return delay_;
}
+ // Start the timer to run at the given |delay| from now. If the timer is
+ // already running, it will be replaced to call the given |user_task|.
+ void Start(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task);
+
+ // Call this method to stop and cancel the timer. It is a no-op if the timer
+ // is not running.
+ void Stop();
+
+ // Call this method to reset the timer delay. The user_task_ must be set. If
+ // the timer is not running, this will start it by posting a task.
+ void Reset();
+
+ const base::Closure& user_task() const { return user_task_; }
+
protected:
- BaseTimer_Helper() : delayed_task_(NULL) {}
-
- // We have access to the timer_ member so we can orphan this task.
- class TimerTask {
- public:
- TimerTask(const tracked_objects::Location& posted_from,
- TimeDelta delay)
- : posted_from_(posted_from),
- timer_(NULL),
- delay_(delay) {
- }
- virtual ~TimerTask() {}
- virtual void Run() = 0;
- tracked_objects::Location posted_from_;
- BaseTimer_Helper* timer_;
- TimeDelta delay_;
- };
-
- // Used to orphan delayed_task_ so that when it runs it does nothing.
- void OrphanDelayedTask();
-
- // Used to initiated a new delayed task. This has the side-effect of
- // orphaning delayed_task_ if it is non-null.
- void InitiateDelayedTask(TimerTask* timer_task);
-
- TimerTask* delayed_task_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper);
+ // Used to initiate a new delayed task. This has the side-effect of disabling
+ // scheduled_task_ if it is non-null.
+ void SetTaskInfo(const tracked_objects::Location& posted_from,
+ TimeDelta delay,
+ const base::Closure& user_task);
+
+ private:
+ friend class BaseTimerTaskInternal;
+
+ // Allocates a new scheduled_task_ and posts it on the current MessageLoop
+ // with the given |delay|. scheduled_task_ must be NULL. scheduled_run_time_
+ // and desired_run_time_ are reset to Now() + delay.
+ void PostNewScheduledTask(TimeDelta delay);
+
+ // Disable scheduled_task_ and abandon it so that it no longer refers back to
+ // this object.
+ void AbandonScheduledTask();
+
+ // Called by BaseTimerTaskInternal when the MessageLoop runs it.
+ void RunScheduledTask();
+
+ // Stop running task (if any) and abandon scheduled task (if any).
+ void StopAndAbandon() {
+ Stop();
+ AbandonScheduledTask();
+ }
+
+ // When non-NULL, the scheduled_task_ is waiting in the MessageLoop to call
+ // RunScheduledTask() at scheduled_run_time_.
+ BaseTimerTaskInternal* scheduled_task_;
+
+ // Location in user code.
+ tracked_objects::Location posted_from_;
+ // Delay requested by user.
+ TimeDelta delay_;
+ // user_task_ is what the user wants to be run at desired_run_time_.
+ base::Closure user_task_;
+
+ // The estimated time that the MessageLoop will run the scheduled_task_ that
+ // will call RunScheduledTask().
+ TimeTicks scheduled_run_time_;
+
+ // The desired run time of user_task_. The user may update this at any time,
+ // even if their previous request has not run yet. If desired_run_time_ is
+ // greater than scheduled_run_time_, a continuation task will be posted to
+ // wait for the remaining time. This allows us to reuse the pending task so as
+ // not to flood the MessageLoop with orphaned tasks when the user code
+ // excessively Stops and Starts the timer.
+ TimeTicks desired_run_time_;
+
+ // Thread ID of current MessageLoop for verifying single-threaded usage.
+ int thread_id_;
+
+ // Repeating timers automatically post the task again before calling the task
+ // callback.
+ const bool is_repeating_;
+
+ // If true, hold on to the user_task_ closure object for reuse.
+ const bool retain_user_task_;
+
+ // If true, user_task_ is scheduled to run sometime in the future.
+ bool is_running_;
+
+ DISALLOW_COPY_AND_ASSIGN(Timer);
};
//-----------------------------------------------------------------------------
// This class is an implementation detail of OneShotTimer and RepeatingTimer.
// Please do not use this class directly.
template <class Receiver, bool kIsRepeating>
-class BaseTimer : public BaseTimer_Helper {
+class BaseTimerMethodPointer : public Timer {
public:
typedef void (Receiver::*ReceiverMethod)();
- // Call this method to start the timer. It is an error to call this method
- // while the timer is already running.
+ BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+
+ // Start the timer to run at the given |delay| from now. If the timer is
+ // already running, it will be replaced to call a task formed from
+ // |reviewer->*method|.
void Start(const tracked_objects::Location& posted_from,
TimeDelta delay,
Receiver* receiver,
ReceiverMethod method) {
- DCHECK(!IsRunning());
- InitiateDelayedTask(new TimerTask(posted_from, delay, receiver, method));
+ Timer::Start(posted_from, delay,
+ base::Bind(method, base::Unretained(receiver)));
}
-
- // Call this method to stop the timer. It is a no-op if the timer is not
- // running.
- void Stop() {
- OrphanDelayedTask();
- }
-
- // Call this method to reset the timer delay of an already running timer.
- void Reset() {
- DCHECK(IsRunning());
- InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone());
- }
-
- private:
- typedef BaseTimer<Receiver, kIsRepeating> SelfType;
-
- class TimerTask : public BaseTimer_Helper::TimerTask {
- public:
- TimerTask(const tracked_objects::Location& posted_from,
- TimeDelta delay,
- Receiver* receiver,
- ReceiverMethod method)
- : BaseTimer_Helper::TimerTask(posted_from, delay),
- receiver_(receiver),
- method_(method) {
- }
-
- virtual ~TimerTask() {
- // This task may be getting cleared because the MessageLoop has been
- // destructed. If so, don't leave the Timer with a dangling pointer
- // to this now-defunct task.
- ClearBaseTimer();
- }
-
- virtual void Run() {
- if (!timer_) // timer_ is null if we were orphaned.
- return;
- if (kIsRepeating)
- ResetBaseTimer();
- else
- ClearBaseTimer();
- (receiver_->*method_)();
- }
-
- TimerTask* Clone() const {
- return new TimerTask(posted_from_, delay_, receiver_, method_);
- }
-
- private:
- // Inform the Base that the timer is no longer active.
- void ClearBaseTimer() {
- if (timer_) {
- SelfType* self = static_cast<SelfType*>(timer_);
- // It is possible that the Timer has already been reset, and that this
- // Task is old. So, if the Timer points to a different task, assume
- // that the Timer has already taken care of properly setting the task.
- if (self->delayed_task_ == this)
- self->delayed_task_ = NULL;
- // By now the delayed_task_ in the Timer does not point to us anymore.
- // We should reset our own timer_ because the Timer can not do this
- // for us in its destructor.
- timer_ = NULL;
- }
- }
-
- // Inform the Base that we're resetting the timer.
- void ResetBaseTimer() {
- DCHECK(timer_);
- DCHECK(kIsRepeating);
- SelfType* self = static_cast<SelfType*>(timer_);
- self->Reset();
- }
-
- Receiver* receiver_;
- ReceiverMethod method_;
- };
};
//-----------------------------------------------------------------------------
// A simple, one-shot timer. See usage notes at the top of the file.
template <class Receiver>
-class OneShotTimer : public BaseTimer<Receiver, false> {};
+class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
//-----------------------------------------------------------------------------
// A simple, repeating timer. See usage notes at the top of the file.
template <class Receiver>
-class RepeatingTimer : public BaseTimer<Receiver, true> {};
+class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
//-----------------------------------------------------------------------------
// A Delay timer is like The Button from Lost. Once started, you have to keep
@@ -230,7 +220,7 @@ class RepeatingTimer : public BaseTimer<Receiver, true> {};
// If destroyed, the timeout is canceled and will not occur even if already
// inflight.
template <class Receiver>
-class DelayTimer {
+class DelayTimer : protected Timer {
public:
typedef void (Receiver::*ReceiverMethod)();
@@ -238,51 +228,11 @@ class DelayTimer {
TimeDelta delay,
Receiver* receiver,
ReceiverMethod method)
- : posted_from_(posted_from),
- receiver_(receiver),
- method_(method),
- delay_(delay) {
- }
-
- void Reset() {
- DelayFor(delay_);
- }
-
- private:
- void DelayFor(TimeDelta delay) {
- trigger_time_ = TimeTicks::Now() + delay;
-
- // If we already have a timer that will expire at or before the given delay,
- // then we have nothing more to do now.
- if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay)
- return;
-
- // The timer isn't running, or will expire too late, so restart it.
- timer_.Stop();
- timer_.Start(posted_from_, delay, this, &DelayTimer<Receiver>::Check);
- }
-
- void Check() {
- if (trigger_time_.is_null())
- return;
-
- // If we have not waited long enough, then wait some more.
- const TimeTicks now = TimeTicks::Now();
- if (now < trigger_time_) {
- DelayFor(trigger_time_ - now);
- return;
- }
-
- (receiver_->*method_)();
- }
-
- tracked_objects::Location posted_from_;
- Receiver *const receiver_;
- const ReceiverMethod method_;
- const TimeDelta delay_;
+ : Timer(posted_from, delay,
+ base::Bind(method, base::Unretained(receiver)),
+ false) {}
- OneShotTimer<DelayTimer<Receiver> > timer_;
- TimeTicks trigger_time_;
+ void Reset() { Timer::Reset(); }
};
} // namespace base
diff --git a/base/timer_unittest.cc b/base/timer_unittest.cc
index 929bd38..71a752e 100644
--- a/base/timer_unittest.cc
+++ b/base/timer_unittest.cc
@@ -352,3 +352,126 @@ TEST(TimerTest, MessageLoopShutdown) {
EXPECT_FALSE(did_run);
}
+
+void TimerTestCallback() {
+}
+
+TEST(TimerTest, NonRepeatIsRunning) {
+ {
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ base::Timer timer(false, false);
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+ base::Bind(&TimerTestCallback));
+ EXPECT_TRUE(timer.IsRunning());
+ timer.Stop();
+ EXPECT_FALSE(timer.IsRunning());
+ EXPECT_TRUE(timer.user_task().is_null());
+ }
+
+ {
+ base::Timer timer(true, false);
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+ base::Bind(&TimerTestCallback));
+ EXPECT_TRUE(timer.IsRunning());
+ timer.Stop();
+ EXPECT_FALSE(timer.IsRunning());
+ ASSERT_FALSE(timer.user_task().is_null());
+ timer.Reset();
+ EXPECT_TRUE(timer.IsRunning());
+ }
+}
+
+TEST(TimerTest, NonRepeatMessageLoopDeath) {
+ base::Timer timer(false, false);
+ {
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+ base::Bind(&TimerTestCallback));
+ EXPECT_TRUE(timer.IsRunning());
+ }
+ EXPECT_FALSE(timer.IsRunning());
+ EXPECT_TRUE(timer.user_task().is_null());
+}
+
+TEST(TimerTest, RetainRepeatIsRunning) {
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+ base::Bind(&TimerTestCallback), true);
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Reset();
+ EXPECT_TRUE(timer.IsRunning());
+ timer.Stop();
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Reset();
+ EXPECT_TRUE(timer.IsRunning());
+}
+
+TEST(TimerTest, RetainNonRepeatIsRunning) {
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+ base::Bind(&TimerTestCallback), false);
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Reset();
+ EXPECT_TRUE(timer.IsRunning());
+ timer.Stop();
+ EXPECT_FALSE(timer.IsRunning());
+ timer.Reset();
+ EXPECT_TRUE(timer.IsRunning());
+}
+
+namespace {
+
+bool g_callback_happened1 = false;
+bool g_callback_happened2 = false;
+
+void ClearAllCallbackHappened() {
+ g_callback_happened1 = false;
+ g_callback_happened2 = false;
+}
+
+void SetCallbackHappened1() {
+ g_callback_happened1 = true;
+ MessageLoop::current()->Quit();
+}
+
+void SetCallbackHappened2() {
+ g_callback_happened2 = true;
+ MessageLoop::current()->Quit();
+}
+
+TEST(TimerTest, ContinuationStopStart) {
+ {
+ ClearAllCallbackHappened();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ base::Timer timer(false, false);
+ timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+ base::Bind(&SetCallbackHappened1));
+ timer.Stop();
+ timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40),
+ base::Bind(&SetCallbackHappened2));
+ MessageLoop::current()->Run();
+ EXPECT_FALSE(g_callback_happened1);
+ EXPECT_TRUE(g_callback_happened2);
+ }
+}
+
+TEST(TimerTest, ContinuationReset) {
+ {
+ ClearAllCallbackHappened();
+ MessageLoop loop(MessageLoop::TYPE_DEFAULT);
+ base::Timer timer(false, false);
+ timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+ base::Bind(&SetCallbackHappened1));
+ timer.Reset();
+ // Since Reset happened before task ran, the user_task must not be cleared:
+ ASSERT_FALSE(timer.user_task().is_null());
+ MessageLoop::current()->Run();
+ EXPECT_TRUE(g_callback_happened1);
+ }
+}
+
+} // namespace
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 587bc4f..78597e5 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -127,7 +127,7 @@ namespace {
// REVIEWERS: Do not let anyone increment this. We need to drive the number of
// raw accessed services down to zero. DO NOT LET PEOPLE REGRESS THIS UNLESS
// THE PATCH ITSELF IS MAKING PROGRESS ON PKSF REFACTORING.
-COMPILE_ASSERT(sizeof(ProfileImpl) <= 720u, profile_impl_size_unexpected);
+COMPILE_ASSERT(sizeof(ProfileImpl) <= 744u, profile_impl_size_unexpected);
#endif
// Delay, in milliseconds, before we explicitly create the SessionService.
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 3e0100f..65910cde 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -220,7 +220,7 @@ class SyncBackendHost::Core
SyncBackendRegistrar* registrar_;
// The timer used to periodically call SaveChanges.
- base::RepeatingTimer<Core> save_changes_timer_;
+ scoped_ptr<base::RepeatingTimer<Core> > save_changes_timer_;
// Our encryptor, which uses Chrome's encryption functions.
ChromeEncryptor encryptor_;
@@ -1149,7 +1149,7 @@ void SyncBackendHost::Core::DoShutdown(bool sync_disabled) {
if (!sync_manager_.get())
return;
- save_changes_timer_.Stop();
+ save_changes_timer_.reset();
sync_manager_->ShutdownOnSyncThread();
sync_manager_->RemoveObserver(this);
sync_manager_.reset();
@@ -1196,7 +1196,9 @@ void SyncBackendHost::Core::StartSavingChanges() {
if (!sync_loop_)
return;
DCHECK_EQ(MessageLoop::current(), sync_loop_);
- save_changes_timer_.Start(FROM_HERE,
+ DCHECK(!save_changes_timer_.get());
+ save_changes_timer_.reset(new base::RepeatingTimer<Core>());
+ save_changes_timer_->Start(FROM_HERE,
base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds),
this, &Core::SaveChanges);
}
diff --git a/content/browser/download/download_file_manager.cc b/content/browser/download/download_file_manager.cc
index 82aba33..b7ab899 100644
--- a/content/browser/download/download_file_manager.cc
+++ b/content/browser/download/download_file_manager.cc
@@ -140,16 +140,20 @@ DownloadFile* DownloadFileManager::GetDownloadFile(
void DownloadFileManager::StartUpdateTimer() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- if (!update_timer_.IsRunning()) {
- update_timer_.Start(FROM_HERE,
- base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
- this, &DownloadFileManager::UpdateInProgressDownloads);
+ if (!update_timer_.get())
+ update_timer_.reset(new base::RepeatingTimer<DownloadFileManager>());
+ if (!update_timer_->IsRunning()) {
+ update_timer_->Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
+ this, &DownloadFileManager::UpdateInProgressDownloads);
}
}
void DownloadFileManager::StopUpdateTimer() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- update_timer_.Stop();
+ // Destroy the timer now. We can't wait until ~DownloadFileManager, because it
+ // may happen on another thread and timers don't allow that.
+ update_timer_.reset();
}
void DownloadFileManager::UpdateInProgressDownloads() {
diff --git a/content/browser/download/download_file_manager.h b/content/browser/download/download_file_manager.h
index df067d8..f75c8e0 100644
--- a/content/browser/download/download_file_manager.h
+++ b/content/browser/download/download_file_manager.h
@@ -195,7 +195,7 @@ class CONTENT_EXPORT DownloadFileManager
// Schedule periodic updates of the download progress. This timer
// is controlled from the FILE thread, and posts updates to the UI thread.
- base::RepeatingTimer<DownloadFileManager> update_timer_;
+ scoped_ptr<base::RepeatingTimer<DownloadFileManager> > update_timer_;
scoped_ptr<DownloadFileFactory> download_file_factory_;
diff --git a/content/browser/in_process_webkit/webkit_thread.cc b/content/browser/in_process_webkit/webkit_thread.cc
index bb1ae40..db0cd07 100644
--- a/content/browser/in_process_webkit/webkit_thread.cc
+++ b/content/browser/in_process_webkit/webkit_thread.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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.
@@ -66,6 +66,10 @@ void WebKitThread::InternalWebKitThread::Init() {
void WebKitThread::InternalWebKitThread::CleanUp() {
DCHECK(webkit_platform_support_.get());
WebKit::shutdown();
+ // Delete BrowserWebKitPlatformSupportImpl now while on the same thread that
+ // constructed it. (This prevents the WebKit shared timer from being destroyed
+ // on a different thread than the one using it.)
+ webkit_platform_support_.reset();
}
} // namespace content
diff --git a/content/browser/renderer_host/resource_dispatcher_host_impl.cc b/content/browser/renderer_host/resource_dispatcher_host_impl.cc
index 409f119..d7ea8ad 100644
--- a/content/browser/renderer_host/resource_dispatcher_host_impl.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host_impl.cc
@@ -338,6 +338,9 @@ ResourceDispatcherHostImpl::ResourceDispatcherHostImpl()
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&appcache::AppCacheInterceptor::EnsureRegistered));
+
+ update_load_states_timer_.reset(
+ new base::RepeatingTimer<ResourceDispatcherHostImpl>());
}
ResourceDispatcherHostImpl::~ResourceDispatcherHostImpl() {
@@ -605,7 +608,7 @@ void ResourceDispatcherHostImpl::OnShutdown() {
// Make sure we shutdown the timer now, otherwise by the time our destructor
// runs if the timer is still running the Task is deleted twice (once by
// the MessageLoop and the second time by RepeatingTimer).
- update_load_states_timer_.Stop();
+ update_load_states_timer_.reset();
// Clear blocked requests if any left.
// Note that we have to do this in 2 passes as we cannot call
@@ -1368,8 +1371,8 @@ void ResourceDispatcherHostImpl::RemovePendingRequest(
pending_requests_.erase(iter);
// If we have no more pending requests, then stop the load state monitor
- if (pending_requests_.empty())
- update_load_states_timer_.Stop();
+ if (pending_requests_.empty() && update_load_states_timer_.get())
+ update_load_states_timer_->Stop();
}
// net::URLRequest::Delegate ---------------------------------------------------
@@ -1731,8 +1734,8 @@ void ResourceDispatcherHostImpl::StartRequest(net::URLRequest* request) {
request->Start();
// Make sure we have the load state monitor running
- if (!update_load_states_timer_.IsRunning()) {
- update_load_states_timer_.Start(FROM_HERE,
+ if (!update_load_states_timer_->IsRunning()) {
+ update_load_states_timer_->Start(FROM_HERE,
TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec),
this, &ResourceDispatcherHostImpl::UpdateLoadStates);
}
diff --git a/content/browser/renderer_host/resource_dispatcher_host_impl.h b/content/browser/renderer_host/resource_dispatcher_host_impl.h
index 6238550..eab5e78 100644
--- a/content/browser/renderer_host/resource_dispatcher_host_impl.h
+++ b/content/browser/renderer_host/resource_dispatcher_host_impl.h
@@ -441,7 +441,8 @@ class CONTENT_EXPORT ResourceDispatcherHostImpl
// A timer that periodically calls UpdateLoadStates while pending_requests_
// is not empty.
- base::RepeatingTimer<ResourceDispatcherHostImpl> update_load_states_timer_;
+ scoped_ptr<base::RepeatingTimer<ResourceDispatcherHostImpl> >
+ update_load_states_timer_;
// We own the download file writing thread and manager
scoped_refptr<DownloadFileManager> download_file_manager_;
diff --git a/content/common/net/url_fetcher_impl.cc b/content/common/net/url_fetcher_impl.cc
index 9dd3cd3..0e87c51 100644
--- a/content/common/net/url_fetcher_impl.cc
+++ b/content/common/net/url_fetcher_impl.cc
@@ -316,7 +316,8 @@ class URLFetcherImpl::Core
base::TimeDelta backoff_delay_;
// Timer to poll the progress of uploading for POST and PUT requests.
- base::RepeatingTimer<Core> upload_progress_checker_timer_;
+ // When crbug.com/119629 is fixed, scoped_ptr is not necessary here.
+ scoped_ptr<base::RepeatingTimer<Core> > upload_progress_checker_timer_;
// Number of bytes sent so far.
int64 current_upload_bytes_;
// Number of bytes received so far.
@@ -903,7 +904,8 @@ void URLFetcherImpl::Core::StartURLRequest() {
current_upload_bytes_ = -1;
// TODO(kinaba): http://crbug.com/118103. Implement upload callback in the
// net:: layer and avoid using timer here.
- upload_progress_checker_timer_.Start(
+ upload_progress_checker_timer_.reset(new base::RepeatingTimer<Core>());
+ upload_progress_checker_timer_->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kUploadProgressTimerInterval),
this,
@@ -1050,7 +1052,7 @@ void URLFetcherImpl::Core::NotifyMalformedContent() {
}
void URLFetcherImpl::Core::ReleaseRequest() {
- upload_progress_checker_timer_.Stop();
+ upload_progress_checker_timer_.reset();
request_.reset();
g_registry.Get().RemoveURLFetcherCore(this);
}
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index 67623da..bf6f2ea 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -23,13 +23,13 @@ AudioInputController::AudioInputController(EventHandler* handler,
: creator_loop_(base::MessageLoopProxy::current()),
handler_(handler),
stream_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(no_data_timer_(FROM_HERE,
- base::TimeDelta::FromSeconds(kTimerResetInterval),
- this,
- &AudioInputController::DoReportNoDataError)),
state_(kEmpty),
sync_writer_(sync_writer) {
DCHECK(creator_loop_);
+ no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE,
+ base::TimeDelta::FromSeconds(kTimerResetInterval),
+ this,
+ &AudioInputController::DoReportNoDataError));
}
AudioInputController::~AudioInputController() {
@@ -103,6 +103,11 @@ void AudioInputController::Record() {
void AudioInputController::Close(const base::Closure& closed_task) {
DCHECK(!closed_task.is_null());
+ DCHECK(creator_loop_->BelongsToCurrentThread());
+ // See crbug.com/119783: Deleting the timer now to avoid disaster if
+ // AudioInputController is destructed on a thread other than the creator
+ // thread.
+ no_data_timer_.reset();
message_loop_->PostTaskAndReply(
FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
}
@@ -180,7 +185,8 @@ void AudioInputController::DoReportNoDataError() {
void AudioInputController::DoResetNoDataTimer() {
DCHECK(creator_loop_->BelongsToCurrentThread());
- no_data_timer_.Reset();
+ if (no_data_timer_.get())
+ no_data_timer_->Reset();
}
void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
diff --git a/media/audio/audio_input_controller.h b/media/audio/audio_input_controller.h
index 88cfb80..feeb895 100644
--- a/media/audio/audio_input_controller.h
+++ b/media/audio/audio_input_controller.h
@@ -144,7 +144,7 @@ class MEDIA_EXPORT AudioInputController
SyncWriter* sync_writer);
// Starts recording using the created audio input stream.
- // This method is called on the audio thread.
+ // This method is called on the creator thread.
virtual void Record();
// Closes the audio input stream. The state is changed and the resources
@@ -215,7 +215,7 @@ class MEDIA_EXPORT AudioInputController
// when an audio input device is unplugged whilst recording on Windows.
// See http://crbug.com/79936 for details.
// This member is only touched by the creating thread.
- base::DelayTimer<AudioInputController> no_data_timer_;
+ scoped_ptr<base::DelayTimer<AudioInputController> > no_data_timer_;
// |state_| is written on the audio thread and is read on the hardware audio
// thread. These operations need to be locked. But lock is not required for
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index aa232c3..1f08b15 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -423,8 +423,9 @@ int BackendImpl::SyncInit() {
trace_object_ = TraceObject::GetTraceObject();
// Create a recurrent timer of 30 secs.
int timer_delay = unit_test_ ? 1000 : 30000;
- timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(timer_delay), this,
- &BackendImpl::OnStatsTimer);
+ timer_.reset(new base::RepeatingTimer<BackendImpl>());
+ timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(timer_delay), this,
+ &BackendImpl::OnStatsTimer);
}
init_ = true;
@@ -497,7 +498,7 @@ int BackendImpl::SyncInit() {
void BackendImpl::CleanupCache() {
Trace("Backend Cleanup");
eviction_.Stop();
- timer_.Stop();
+ timer_.reset();
if (init_) {
stats_.Store();
diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h
index e2fb6ef..663f7fc 100644
--- a/net/disk_cache/backend_impl.h
+++ b/net/disk_cache/backend_impl.h
@@ -383,7 +383,7 @@ class NET_EXPORT_PRIVATE BackendImpl : public Backend {
net::NetLog* net_log_;
Stats stats_; // Usage statistics.
- base::RepeatingTimer<BackendImpl> timer_; // Usage timer.
+ scoped_ptr<base::RepeatingTimer<BackendImpl> > timer_; // Usage timer.
base::WaitableEvent done_; // Signals the end of background work.
scoped_refptr<TraceObject> trace_object_; // Initializes internal tracing.
base::WeakPtrFactory<BackendImpl> ptr_factory_;
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 7306995..c568028 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -246,8 +246,10 @@ class TestOneShotGestureSequenceTimer
: public base::OneShotTimer<GestureSequence> {
public:
void ForceTimeout() {
- if (delayed_task_)
- delayed_task_->Run();
+ if (IsRunning()) {
+ user_task().Run();
+ Stop();
+ }
}
};