diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-12 13:21:21 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-12 13:21:21 +0000 |
commit | 6719948d489335b4b679c190a59e4995244a00e0 (patch) | |
tree | d19392a9ddf91bf824999c24e7bfef7b4e3a721d /webkit | |
parent | b7823011f3bf858a0d4baba1252f31831b3f3555 (diff) | |
download | chromium_src-6719948d489335b4b679c190a59e4995244a00e0.zip chromium_src-6719948d489335b4b679c190a59e4995244a00e0.tar.gz chromium_src-6719948d489335b4b679c190a59e4995244a00e0.tar.bz2 |
Add TimedTaskHelper to replace timer on SequencedTaskRunner
The code is based on the ObfuscatedFileUtil's ex-timer code
that replaces timer with PostDelayTask.
BUG=248826
R=tzik@chromium.org
Review URL: https://codereview.chromium.org/16775011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205748 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/browser/fileapi/timed_task_helper.cc | 91 | ||||
-rw-r--r-- | webkit/browser/fileapi/timed_task_helper.h | 59 | ||||
-rw-r--r-- | webkit/browser/fileapi/timed_task_helper_unittest.cc | 84 | ||||
-rw-r--r-- | webkit/storage_browser.gyp | 2 |
4 files changed, 236 insertions, 0 deletions
diff --git a/webkit/browser/fileapi/timed_task_helper.cc b/webkit/browser/fileapi/timed_task_helper.cc new file mode 100644 index 0000000..7a33a6a --- /dev/null +++ b/webkit/browser/fileapi/timed_task_helper.cc @@ -0,0 +1,91 @@ +// Copyright 2013 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 "webkit/browser/fileapi/timed_task_helper.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/sequenced_task_runner.h" + +namespace fileapi { + +struct TimedTaskHelper::Tracker { + explicit Tracker(TimedTaskHelper* timer) : timer(timer) {} + + ~Tracker() { + if (timer) + timer->tracker_ = NULL; + } + + TimedTaskHelper* timer; +}; + +TimedTaskHelper::TimedTaskHelper(base::SequencedTaskRunner* task_runner) + : task_runner_(task_runner), + tracker_(NULL) { +} + +TimedTaskHelper::~TimedTaskHelper() { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); + if (tracker_) + tracker_->timer = NULL; +} + +bool TimedTaskHelper::IsRunning() const { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); + return tracker_ != NULL; +} + +void TimedTaskHelper::Start( + const tracked_objects::Location& posted_from, + base::TimeDelta delay, + const base::Closure& user_task) { + posted_from_ = posted_from; + delay_ = delay; + user_task_ = user_task; + Reset(); +} + +void TimedTaskHelper::Reset() { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!user_task_.is_null()); + desired_run_time_ = base::TimeTicks::Now() + delay_; + + if (tracker_) + return; + + // Initialize the tracker for the first time. + tracker_ = new Tracker(this); + PostDelayedTask(make_scoped_ptr(tracker_), delay_); +} + +// static +void TimedTaskHelper::Fired(scoped_ptr<Tracker> tracker) { + if (!tracker->timer) + return; + TimedTaskHelper* timer = tracker->timer; + timer->OnFired(tracker.Pass()); +} + +void TimedTaskHelper::OnFired(scoped_ptr<Tracker> tracker) { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); + base::TimeTicks now = base::TimeTicks::Now(); + if (desired_run_time_ > now) { + PostDelayedTask(tracker.Pass(), desired_run_time_ - now); + return; + } + tracker.reset(); + user_task_.Run(); + user_task_.Reset(); +} + +void TimedTaskHelper::PostDelayedTask(scoped_ptr<Tracker> tracker, + base::TimeDelta delay) { + task_runner_->PostDelayedTask( + posted_from_, + base::Bind(&TimedTaskHelper::Fired, base::Passed(&tracker)), + delay); +} + +} // namespace fileapi diff --git a/webkit/browser/fileapi/timed_task_helper.h b/webkit/browser/fileapi/timed_task_helper.h new file mode 100644 index 0000000..ad72fb8 --- /dev/null +++ b/webkit/browser/fileapi/timed_task_helper.h @@ -0,0 +1,59 @@ +// Copyright 2013 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. + +#ifndef WEBKIT_BROWSER_FILEAPI_TIMED_TASK_HELPER_H_ +#define WEBKIT_BROWSER_FILEAPI_TIMED_TASK_HELPER_H_ + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/time.h" +#include "webkit/storage/webkit_storage_export.h" + +namespace base { +class SequencedTaskRunner; +} + +namespace fileapi { + +// Works similarly as base::Timer, but takes SequencedTaskRunner and +// runs tasks on it (instead of implicitly bound to a thread). +// TODO(kinuko): This has nothing to do with fileapi. Move somewhere +// more common place. +class WEBKIT_STORAGE_EXPORT TimedTaskHelper { + public: + explicit TimedTaskHelper(base::SequencedTaskRunner* task_runner); + ~TimedTaskHelper(); + + bool IsRunning() const; + void Start(const tracked_objects::Location& posted_from, + base::TimeDelta delay, + const base::Closure& user_task); + void Reset(); + + private: + struct Tracker; + static void Fired(scoped_ptr<Tracker> tracker); + + void OnFired(scoped_ptr<Tracker> tracker); + void PostDelayedTask(scoped_ptr<Tracker> tracker, base::TimeDelta delay); + + scoped_refptr<base::SequencedTaskRunner> task_runner_; + tracked_objects::Location posted_from_; + base::TimeDelta delay_; + base::Closure user_task_; + + base::TimeTicks desired_run_time_; + + // This is set to non-null and owned by a timer task while timer is running. + Tracker* tracker_; + + DISALLOW_COPY_AND_ASSIGN(TimedTaskHelper); +}; + +} // namespace fileapi + +#endif // WEBKIT_BROWSER_FILEAPI_TIMED_TASK_HELPER_H_ diff --git a/webkit/browser/fileapi/timed_task_helper_unittest.cc b/webkit/browser/fileapi/timed_task_helper_unittest.cc new file mode 100644 index 0000000..5f11c7e --- /dev/null +++ b/webkit/browser/fileapi/timed_task_helper_unittest.cc @@ -0,0 +1,84 @@ +// Copyright 2013 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 "base/basictypes.h" +#include "base/bind.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "webkit/browser/fileapi/timed_task_helper.h" + +namespace fileapi { + +namespace { + +class Embedder { + public: + Embedder() + : timer_(base::MessageLoopProxy::current()), + timer_fired_(false) {} + + void OnTimerFired() { + timer_fired_ = true; + } + + TimedTaskHelper* timer() { return &timer_; } + bool timer_fired() const { return timer_fired_; } + + private: + TimedTaskHelper timer_; + bool timer_fired_; +}; + +} // namespace + +TEST(TimedTaskHelper, FireTimerWhenAlive) { + base::MessageLoop message_loop; + Embedder embedder; + + ASSERT_FALSE(embedder.timer_fired()); + ASSERT_FALSE(embedder.timer()->IsRunning()); + + embedder.timer()->Start( + FROM_HERE, + base::TimeDelta::FromSeconds(0), + base::Bind(&Embedder::OnTimerFired, base::Unretained(&embedder))); + + ASSERT_TRUE(embedder.timer()->IsRunning()); + embedder.timer()->Reset(); + ASSERT_TRUE(embedder.timer()->IsRunning()); + + base::MessageLoop::current()->RunUntilIdle(); + + ASSERT_TRUE(embedder.timer_fired()); +} + +TEST(TimedTaskHelper, FireTimerWhenAlreadyDeleted) { + base::MessageLoop message_loop; + + // Run message loop after embedder is already deleted to make sure callback + // doesn't cause a crash for use after free. + { + Embedder embedder; + + ASSERT_FALSE(embedder.timer_fired()); + ASSERT_FALSE(embedder.timer()->IsRunning()); + + embedder.timer()->Start( + FROM_HERE, + base::TimeDelta::FromSeconds(0), + base::Bind(&Embedder::OnTimerFired, base::Unretained(&embedder))); + + ASSERT_TRUE(embedder.timer()->IsRunning()); + } + + // At this point the callback is still in the message queue but + // embedder is gone. + base::MessageLoop::current()->RunUntilIdle(); +} + +} // namespace fileapi diff --git a/webkit/storage_browser.gyp b/webkit/storage_browser.gyp index 01b0a22..59afef5 100644 --- a/webkit/storage_browser.gyp +++ b/webkit/storage_browser.gyp @@ -220,6 +220,8 @@ 'browser/fileapi/task_runner_bound_observer_list.h', 'browser/fileapi/test_mount_point_provider.cc', 'browser/fileapi/test_mount_point_provider.h', + 'browser/fileapi/timed_task_helper.cc', + 'browser/fileapi/timed_task_helper.h', 'browser/fileapi/transient_file_util.cc', 'browser/fileapi/transient_file_util.h', 'browser/fileapi/upload_file_system_file_element_reader.cc', |