Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: content/browser/device_orientation/provider_impl.cc

Issue 10835030: device_orientation::ProviderImpl to stop polling thread asynchronously (Closed) Base URL: https://src.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <cmath> 5 #include <cmath>
6 #include <set> 6 #include <set>
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/threading/thread.h" 12 #include "base/threading/thread.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/worker_pool.h"
14 #include "content/browser/device_orientation/orientation.h" 14 #include "content/browser/device_orientation/orientation.h"
15 #include "content/browser/device_orientation/provider_impl.h" 15 #include "content/browser/device_orientation/provider_impl.h"
16 16
17 namespace {
18
19 bool IsElementSignificantlyDifferent(bool can_provide_element1,
20 bool can_provide_element2,
21 double element1,
22 double element2) {
23 const double kThreshold = 0.1;
24
25 if (can_provide_element1 != can_provide_element2)
26 return true;
27 if (can_provide_element1 &&
28 std::fabs(element1 - element2) >= kThreshold)
29 return true;
30 return false;
31 }
32
33 void DeleteThread(base::Thread* thread) {
34 delete thread;
35 }
36
37 }
38
17 namespace device_orientation { 39 namespace device_orientation {
18 40
19 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[]) 41 class ProviderImpl::PollingThread : public base::Thread {
20 : creator_loop_(MessageLoop::current()), 42 public:
21 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 43 PollingThread(const char* name,
22 for (const DataFetcherFactory* fp = factories; *fp; ++fp) 44 base::WeakPtr<ProviderImpl> provider,
23 factories_.push_back(*fp); 45 MessageLoop* creator_loop);
46 virtual ~PollingThread();
47
48 // Method for finding a suitable DataFetcher and starting the polling.
49 void Initialize(const std::vector<DataFetcherFactory>& factories);
50
51 private:
52 // Method for polling a DataFetcher.
53 void DoPoll();
54 void ScheduleDoPoll();
55
56 // Schedule a notification to the |provider_| which lives on a different
57 // thread (|creator_loop_| is its message loop).
58 void ScheduleDoNotify(const Orientation& orientation);
59
60 static bool SignificantlyDifferent(const Orientation& orientation1,
61 const Orientation& orientation2);
62
63 enum { kDesiredSamplingIntervalMs = 100 };
64 base::TimeDelta SamplingInterval() const;
65
66 // The Message Loop on which this object was created.
67 // Typically the I/O loop, but may be something else during testing.
68 MessageLoop* creator_loop_;
69
70 scoped_ptr<DataFetcher> data_fetcher_;
71 Orientation last_orientation_;
72
73 base::WeakPtr<ProviderImpl> provider_;
74 };
75
76 ProviderImpl::PollingThread::PollingThread(
77 const char* name,
78 base::WeakPtr<ProviderImpl> provider,
79 MessageLoop* creator_loop)
80 : base::Thread(name),
81 creator_loop_(creator_loop),
82 provider_(provider) {
24 } 83 }
25 84
26 ProviderImpl::~ProviderImpl() { 85 ProviderImpl::PollingThread::~PollingThread() {
27 } 86 }
28 87
29 void ProviderImpl::AddObserver(Observer* observer) { 88 void ProviderImpl::PollingThread::Initialize(
30 DCHECK(MessageLoop::current() == creator_loop_);
31
32 observers_.insert(observer);
33 if (observers_.size() == 1)
34 Start();
35 else
36 observer->OnOrientationUpdate(last_notification_);
37 }
38
39 void ProviderImpl::RemoveObserver(Observer* observer) {
40 DCHECK(MessageLoop::current() == creator_loop_);
41
42 observers_.erase(observer);
43 if (observers_.empty())
44 Stop();
45 }
46
47 void ProviderImpl::Start() {
48 DCHECK(MessageLoop::current() == creator_loop_);
49 DCHECK(!polling_thread_.get());
50
51 polling_thread_.reset(new base::Thread("Device orientation polling thread"));
52 if (!polling_thread_->Start()) {
53 LOG(ERROR) << "Failed to start device orientation polling thread";
54 polling_thread_.reset();
55 return;
56 }
57 ScheduleInitializePollingThread();
58 }
59
60 void ProviderImpl::Stop() {
61 DCHECK(MessageLoop::current() == creator_loop_);
62
63 // TODO(hans): Don't join the thread. See crbug.com/72286.
64 base::ThreadRestrictions::ScopedAllowIO allow_io;
65
66 polling_thread_.reset();
67 data_fetcher_.reset();
68 }
69
70 void ProviderImpl::DoInitializePollingThread(
71 const std::vector<DataFetcherFactory>& factories) { 89 const std::vector<DataFetcherFactory>& factories) {
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 90 DCHECK(MessageLoop::current() == message_loop());
73 91
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; 92 typedef std::vector<DataFetcherFactory>::const_iterator Iterator;
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { 93 for (Iterator i = factories.begin(); i != factories.end(); ++i) {
76 DataFetcherFactory factory = *i; 94 DataFetcherFactory factory = *i;
77 scoped_ptr<DataFetcher> fetcher(factory()); 95 scoped_ptr<DataFetcher> fetcher(factory());
78 Orientation orientation; 96 Orientation orientation;
79 97
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { 98 if (fetcher.get() && fetcher->GetOrientation(&orientation)) {
81 // Pass ownership of fetcher to provider_. 99 // Pass ownership of fetcher to provider_.
82 data_fetcher_.swap(fetcher); 100 data_fetcher_.swap(fetcher);
83 last_orientation_ = orientation; 101 last_orientation_ = orientation;
84 102
85 // Notify observers. 103 // Notify observers.
86 if (!orientation.is_empty()) 104 if (!orientation.is_empty())
87 ScheduleDoNotify(orientation); 105 ScheduleDoNotify(orientation);
88 106
89 // Start polling. 107 // Start polling.
90 ScheduleDoPoll(); 108 ScheduleDoPoll();
91 return; 109 return;
92 } 110 }
93 } 111 }
94 112
95 // When no orientation data can be provided. 113 // When no orientation data can be provided.
96 ScheduleDoNotify(Orientation::Empty()); 114 ScheduleDoNotify(Orientation::Empty());
97 } 115 }
98 116
99 void ProviderImpl::ScheduleInitializePollingThread() { 117 void ProviderImpl::PollingThread::ScheduleDoNotify(
100 DCHECK(MessageLoop::current() == creator_loop_); 118 const Orientation& orientation) {
119 DCHECK(MessageLoop::current() == message_loop());
101 120
102 MessageLoop* polling_loop = polling_thread_->message_loop(); 121 creator_loop_->PostTask(
103 polling_loop->PostTask(FROM_HERE, 122 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation));
104 base::Bind(&ProviderImpl::DoInitializePollingThread,
105 this,
106 factories_));
107 } 123 }
108 124
109 void ProviderImpl::DoNotify(const Orientation& orientation) { 125 void ProviderImpl::PollingThread::DoPoll() {
110 DCHECK(MessageLoop::current() == creator_loop_); 126 DCHECK(MessageLoop::current() == message_loop());
111
112 last_notification_ = orientation;
113
114 typedef std::set<Observer*>::const_iterator Iterator;
115 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i)
116 (*i)->OnOrientationUpdate(orientation);
117
118 if (orientation.is_empty()) {
119 // Notify observers about failure to provide data exactly once.
120 observers_.clear();
121 Stop();
122 }
123 }
124
125 void ProviderImpl::ScheduleDoNotify(const Orientation& orientation) {
126 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
127
128 creator_loop_->PostTask(
129 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, this, orientation));
130 }
131
132 void ProviderImpl::DoPoll() {
133 DCHECK(MessageLoop::current() == polling_thread_->message_loop());
134 127
135 Orientation orientation; 128 Orientation orientation;
136 if (!data_fetcher_->GetOrientation(&orientation)) { 129 if (!data_fetcher_->GetOrientation(&orientation)) {
137 LOG(ERROR) << "Failed to poll device orientation data fetcher."; 130 LOG(ERROR) << "Failed to poll device orientation data fetcher.";
138 131
139 ScheduleDoNotify(Orientation::Empty()); 132 ScheduleDoNotify(Orientation::Empty());
140 return; 133 return;
141 } 134 }
142 135
143 if (!orientation.is_empty() && 136 if (!orientation.is_empty() &&
144 SignificantlyDifferent(orientation, last_orientation_)) { 137 SignificantlyDifferent(orientation, last_orientation_)) {
145 last_orientation_ = orientation; 138 last_orientation_ = orientation;
146 ScheduleDoNotify(orientation); 139 ScheduleDoNotify(orientation);
147 } 140 }
148 141
149 ScheduleDoPoll(); 142 ScheduleDoPoll();
150 } 143 }
151 144
152 void ProviderImpl::ScheduleDoPoll() { 145 void ProviderImpl::PollingThread::ScheduleDoPoll() {
153 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 146 DCHECK(MessageLoop::current() == message_loop());
154 147
155 MessageLoop* polling_loop = polling_thread_->message_loop(); 148 message_loop()->PostDelayedTask(
156 polling_loop->PostDelayedTask(
157 FROM_HERE, 149 FROM_HERE,
158 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()), 150 base::Bind(&PollingThread::DoPoll, base::Unretained(this)),
159 SamplingInterval()); 151 SamplingInterval());
160 } 152 }
161 153
162 namespace {
163
164 bool IsElementSignificantlyDifferent(bool can_provide_element1,
165 bool can_provide_element2,
166 double element1,
167 double element2) {
168 const double kThreshold = 0.1;
169
170 if (can_provide_element1 != can_provide_element2)
171 return true;
172 if (can_provide_element1 &&
173 std::fabs(element1 - element2) >= kThreshold)
174 return true;
175 return false;
176 }
177 } // namespace
178
179 // Returns true if two orientations are considered different enough that 154 // Returns true if two orientations are considered different enough that
180 // observers should be notified of the new orientation. 155 // observers should be notified of the new orientation.
181 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1, 156 bool ProviderImpl::PollingThread::SignificantlyDifferent(
182 const Orientation& o2) { 157 const Orientation& o1,
158 const Orientation& o2) {
183 return IsElementSignificantlyDifferent(o1.can_provide_alpha(), 159 return IsElementSignificantlyDifferent(o1.can_provide_alpha(),
184 o2.can_provide_alpha(), 160 o2.can_provide_alpha(),
185 o1.alpha(), 161 o1.alpha(),
186 o2.alpha()) || 162 o2.alpha()) ||
187 IsElementSignificantlyDifferent(o1.can_provide_beta(), 163 IsElementSignificantlyDifferent(o1.can_provide_beta(),
188 o2.can_provide_beta(), 164 o2.can_provide_beta(),
189 o1.beta(), 165 o1.beta(),
190 o2.beta()) || 166 o2.beta()) ||
191 IsElementSignificantlyDifferent(o1.can_provide_gamma(), 167 IsElementSignificantlyDifferent(o1.can_provide_gamma(),
192 o2.can_provide_gamma(), 168 o2.can_provide_gamma(),
193 o1.gamma(), 169 o1.gamma(),
194 o2.gamma()) || 170 o2.gamma()) ||
195 (o1.can_provide_absolute() != o2.can_provide_absolute() || 171 (o1.can_provide_absolute() != o2.can_provide_absolute() ||
196 o1.absolute() != o2.absolute()); 172 o1.absolute() != o2.absolute());
197 } 173 }
198 174
199 base::TimeDelta ProviderImpl::SamplingInterval() const { 175 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
200 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 176 DCHECK(MessageLoop::current() == message_loop());
201 DCHECK(data_fetcher_.get()); 177 DCHECK(data_fetcher_.get());
202 178
203 // TODO(erg): There used to be unused code here, that called a default 179 // TODO(erg): There used to be unused code here, that called a default
204 // implementation on the DataFetcherInterface that was never defined. I'm 180 // implementation on the DataFetcherInterface that was never defined. I'm
205 // removing unused methods from headers. 181 // removing unused methods from headers.
206 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); 182 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
207 } 183 }
208 184
185 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[])
186 : creator_loop_(MessageLoop::current()),
187 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
188 polling_thread_(NULL) {
189 for (const DataFetcherFactory* fp = factories; *fp; ++fp)
190 factories_.push_back(*fp);
191 }
192
193 ProviderImpl::~ProviderImpl() {
194 Stop();
195 }
196
197 void ProviderImpl::AddObserver(Observer* observer) {
198 DCHECK(MessageLoop::current() == creator_loop_);
199
200 observers_.insert(observer);
201 if (observers_.size() == 1)
202 Start();
203 else
204 observer->OnOrientationUpdate(last_notification_);
205 }
206
207 void ProviderImpl::RemoveObserver(Observer* observer) {
208 DCHECK(MessageLoop::current() == creator_loop_);
209
210 observers_.erase(observer);
211 if (observers_.empty())
212 Stop();
213 }
214
215 void ProviderImpl::Start() {
216 DCHECK(MessageLoop::current() == creator_loop_);
217 DCHECK(!polling_thread_);
218
219 polling_thread_ = new PollingThread("Device orientation polling thread",
220 weak_factory_.GetWeakPtr(),
221 creator_loop_);
222 if (!polling_thread_->Start()) {
223 LOG(ERROR) << "Failed to start device orientation polling thread";
224 delete polling_thread_;
225 polling_thread_ = NULL;
226 return;
227 }
228 ScheduleInitializePollingThread();
229 }
230
231 void ProviderImpl::Stop() {
232 DCHECK(MessageLoop::current() == creator_loop_);
233
234 weak_factory_.InvalidateWeakPtrs();
235 if (polling_thread_) {
236 polling_thread_->StopSoon();
237 bool posted = base::WorkerPool::PostTask(
238 FROM_HERE,
239 base::Bind(&DeleteThread, base::Unretained(polling_thread_)),
240 true /* task is slow */);
241 DCHECK(posted);
242 polling_thread_ = NULL;
243 }
244 }
245
246 void ProviderImpl::ScheduleInitializePollingThread() {
247 DCHECK(MessageLoop::current() == creator_loop_);
248
249 MessageLoop* polling_loop = polling_thread_->message_loop();
250 polling_loop->PostTask(FROM_HERE,
251 base::Bind(&PollingThread::Initialize,
252 base::Unretained(polling_thread_),
253 factories_));
254 }
255
256 void ProviderImpl::DoNotify(const Orientation& orientation) {
257 DCHECK(MessageLoop::current() == creator_loop_);
258
259 last_notification_ = orientation;
260
261 typedef std::set<Observer*>::const_iterator Iterator;
262 for (Iterator i = observers_.begin(); i != observers_.end(); ++i)
263 (*i)->OnOrientationUpdate(orientation);
264
265 if (orientation.is_empty()) {
266 // Notify observers about failure to provide data exactly once.
267 observers_.clear();
268 Stop();
269 }
270 }
271
209 } // namespace device_orientation 272 } // namespace device_orientation
OLDNEW
« no previous file with comments | « content/browser/device_orientation/provider_impl.h ('k') | content/browser/device_orientation/provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698