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

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 explicit PollingThread(const char* name,
hans 2012/07/30 12:56:40 nit: no need for explicit here, I think
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() OVERRIDE;
47
48 // Method for finding a suitable DataFetcher and starting the polling.
49 void InitializePollingThread(
hans 2012/07/30 12:56:40 since it's a member of PollingThread, I think just
50 const std::vector<DataFetcherFactory>& factories);
51
52 private:
53 // Method for polling a DataFetcher.
54 void DoPoll();
55 void ScheduleDoPoll();
56
57 // Schedule a notification to the |provider_| which lives on a different
58 // thread (|creator_loop_| is its message loop).
59 void ScheduleDoNotify(const Orientation& orientation);
60
61 static bool SignificantlyDifferent(const Orientation& orientation1,
62 const Orientation& orientation2);
63
64 enum { kDesiredSamplingIntervalMs = 100 };
65 base::TimeDelta SamplingInterval() const;
66
67 // The Message Loop on which this object was created.
68 // Typically the I/O loop, but may be something else during testing.
69 MessageLoop* creator_loop_;
70
71 scoped_ptr<DataFetcher> data_fetcher_;
72 Orientation last_orientation_;
73
74 base::WeakPtr<ProviderImpl> provider_;
75 };
76
77 ProviderImpl::PollingThread::PollingThread(
78 const char* name,
79 base::WeakPtr<ProviderImpl> provider,
80 MessageLoop* creator_loop)
81 : base::Thread(name),
hans 2012/07/30 12:56:40 nit indentation looks off here: there should be fo
82 creator_loop_(creator_loop),
83 provider_(provider) {
24 } 84 }
25 85
26 ProviderImpl::~ProviderImpl() { 86 ProviderImpl::PollingThread::~PollingThread() {
27 } 87 }
28 88
29 void ProviderImpl::AddObserver(Observer* observer) { 89 void ProviderImpl::PollingThread::InitializePollingThread(
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) { 90 const std::vector<DataFetcherFactory>& factories) {
72 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 91 DCHECK(MessageLoop::current() == message_loop());
73 92
74 typedef std::vector<DataFetcherFactory>::const_iterator Iterator; 93 typedef std::vector<DataFetcherFactory>::const_iterator Iterator;
75 for (Iterator i = factories_.begin(), e = factories_.end(); i != e; ++i) { 94 for (Iterator i = factories.begin(), e = factories.end(); i != e; ++i) {
hans 2012/07/30 12:56:40 nit: since you're touching this line anyway, feel
76 DataFetcherFactory factory = *i; 95 DataFetcherFactory factory = *i;
77 scoped_ptr<DataFetcher> fetcher(factory()); 96 scoped_ptr<DataFetcher> fetcher(factory());
78 Orientation orientation; 97 Orientation orientation;
79 98
80 if (fetcher.get() && fetcher->GetOrientation(&orientation)) { 99 if (fetcher.get() && fetcher->GetOrientation(&orientation)) {
81 // Pass ownership of fetcher to provider_. 100 // Pass ownership of fetcher to provider_.
82 data_fetcher_.swap(fetcher); 101 data_fetcher_.swap(fetcher);
83 last_orientation_ = orientation; 102 last_orientation_ = orientation;
84 103
85 // Notify observers. 104 // Notify observers.
86 if (!orientation.is_empty()) 105 if (!orientation.is_empty())
87 ScheduleDoNotify(orientation); 106 ScheduleDoNotify(orientation);
88 107
89 // Start polling. 108 // Start polling.
90 ScheduleDoPoll(); 109 ScheduleDoPoll();
91 return; 110 return;
92 } 111 }
93 } 112 }
94 113
95 // When no orientation data can be provided. 114 // When no orientation data can be provided.
96 ScheduleDoNotify(Orientation::Empty()); 115 ScheduleDoNotify(Orientation::Empty());
97 } 116 }
98 117
99 void ProviderImpl::ScheduleInitializePollingThread() { 118 void ProviderImpl::PollingThread::ScheduleDoNotify(
100 DCHECK(MessageLoop::current() == creator_loop_); 119 const Orientation& orientation) {
120 DCHECK(MessageLoop::current() == message_loop());
101 121
102 MessageLoop* polling_loop = polling_thread_->message_loop(); 122 creator_loop_->PostTask(
103 polling_loop->PostTask(FROM_HERE, 123 FROM_HERE, base::Bind(&ProviderImpl::DoNotify, provider_, orientation));
104 base::Bind(&ProviderImpl::DoInitializePollingThread,
105 this,
106 factories_));
107 } 124 }
108 125
109 void ProviderImpl::DoNotify(const Orientation& orientation) { 126 void ProviderImpl::PollingThread::DoPoll() {
110 DCHECK(MessageLoop::current() == creator_loop_); 127 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 128
135 Orientation orientation; 129 Orientation orientation;
136 if (!data_fetcher_->GetOrientation(&orientation)) { 130 if (!data_fetcher_->GetOrientation(&orientation)) {
137 LOG(ERROR) << "Failed to poll device orientation data fetcher."; 131 LOG(ERROR) << "Failed to poll device orientation data fetcher.";
138 132
139 ScheduleDoNotify(Orientation::Empty()); 133 ScheduleDoNotify(Orientation::Empty());
140 return; 134 return;
141 } 135 }
142 136
143 if (!orientation.is_empty() && 137 if (!orientation.is_empty() &&
144 SignificantlyDifferent(orientation, last_orientation_)) { 138 SignificantlyDifferent(orientation, last_orientation_)) {
145 last_orientation_ = orientation; 139 last_orientation_ = orientation;
146 ScheduleDoNotify(orientation); 140 ScheduleDoNotify(orientation);
147 } 141 }
148 142
149 ScheduleDoPoll(); 143 ScheduleDoPoll();
150 } 144 }
151 145
152 void ProviderImpl::ScheduleDoPoll() { 146 void ProviderImpl::PollingThread::ScheduleDoPoll() {
153 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 147 DCHECK(MessageLoop::current() == message_loop());
154 148
155 MessageLoop* polling_loop = polling_thread_->message_loop(); 149 message_loop()->PostDelayedTask(
156 polling_loop->PostDelayedTask(
157 FROM_HERE, 150 FROM_HERE,
158 base::Bind(&ProviderImpl::DoPoll, weak_factory_.GetWeakPtr()), 151 base::Bind(&PollingThread::DoPoll, base::Unretained(this)),
159 SamplingInterval()); 152 SamplingInterval());
160 } 153 }
161 154
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 155 // Returns true if two orientations are considered different enough that
180 // observers should be notified of the new orientation. 156 // observers should be notified of the new orientation.
181 bool ProviderImpl::SignificantlyDifferent(const Orientation& o1, 157 bool ProviderImpl::PollingThread::SignificantlyDifferent(
182 const Orientation& o2) { 158 const Orientation& o1,
159 const Orientation& o2) {
183 return IsElementSignificantlyDifferent(o1.can_provide_alpha(), 160 return IsElementSignificantlyDifferent(o1.can_provide_alpha(),
184 o2.can_provide_alpha(), 161 o2.can_provide_alpha(),
185 o1.alpha(), 162 o1.alpha(),
186 o2.alpha()) || 163 o2.alpha()) ||
187 IsElementSignificantlyDifferent(o1.can_provide_beta(), 164 IsElementSignificantlyDifferent(o1.can_provide_beta(),
188 o2.can_provide_beta(), 165 o2.can_provide_beta(),
189 o1.beta(), 166 o1.beta(),
190 o2.beta()) || 167 o2.beta()) ||
191 IsElementSignificantlyDifferent(o1.can_provide_gamma(), 168 IsElementSignificantlyDifferent(o1.can_provide_gamma(),
192 o2.can_provide_gamma(), 169 o2.can_provide_gamma(),
193 o1.gamma(), 170 o1.gamma(),
194 o2.gamma()) || 171 o2.gamma()) ||
195 (o1.can_provide_absolute() != o2.can_provide_absolute() || 172 (o1.can_provide_absolute() != o2.can_provide_absolute() ||
196 o1.absolute() != o2.absolute()); 173 o1.absolute() != o2.absolute());
197 } 174 }
198 175
199 base::TimeDelta ProviderImpl::SamplingInterval() const { 176 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
200 DCHECK(MessageLoop::current() == polling_thread_->message_loop()); 177 DCHECK(MessageLoop::current() == message_loop());
201 DCHECK(data_fetcher_.get()); 178 DCHECK(data_fetcher_.get());
202 179
203 // TODO(erg): There used to be unused code here, that called a default 180 // TODO(erg): There used to be unused code here, that called a default
204 // implementation on the DataFetcherInterface that was never defined. I'm 181 // implementation on the DataFetcherInterface that was never defined. I'm
205 // removing unused methods from headers. 182 // removing unused methods from headers.
206 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs); 183 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
207 } 184 }
208 185
186 ProviderImpl::ProviderImpl(const DataFetcherFactory factories[])
187 : creator_loop_(MessageLoop::current()),
188 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
189 polling_thread_(NULL) {
190 for (const DataFetcherFactory* fp = factories; *fp; ++fp)
191 factories_.push_back(*fp);
192 }
193
194 ProviderImpl::~ProviderImpl() {
195 DCHECK(observers_.empty());
196 DCHECK(!polling_thread_);
197 }
198
199 void ProviderImpl::AddObserver(Observer* observer) {
200 DCHECK(MessageLoop::current() == creator_loop_);
201
202 observers_.insert(observer);
203 if (observers_.size() == 1)
204 Start();
205 else
206 observer->OnOrientationUpdate(last_notification_);
207 }
208
209 void ProviderImpl::RemoveObserver(Observer* observer) {
210 DCHECK(MessageLoop::current() == creator_loop_);
211
212 observers_.erase(observer);
213 if (observers_.empty())
214 Stop();
215 }
216
217 void ProviderImpl::Start() {
218 DCHECK(MessageLoop::current() == creator_loop_);
219 DCHECK(!polling_thread_);
220
221 polling_thread_ = new PollingThread("Device orientation polling thread",
222 weak_factory_.GetWeakPtr(),
223 creator_loop_);
224 if (!polling_thread_->Start()) {
225 LOG(ERROR) << "Failed to start device orientation polling thread";
226 delete polling_thread_;
227 polling_thread_ = NULL;
228 return;
229 }
230 ScheduleInitializePollingThread();
231 }
232
233 void ProviderImpl::Stop() {
234 DCHECK(MessageLoop::current() == creator_loop_);
235
236 weak_factory_.InvalidateWeakPtrs();
237 if (polling_thread_) {
238 polling_thread_->StopSoon();
239 bool posted = base::WorkerPool::PostTask(
240 FROM_HERE,
241 base::Bind(&DeleteThread, base::Unretained(polling_thread_)),
242 true /* task is slow */);
243 DCHECK(posted);
244 polling_thread_ = NULL;
245 }
246 }
247
248 void ProviderImpl::ScheduleInitializePollingThread() {
249 DCHECK(MessageLoop::current() == creator_loop_);
250
251 MessageLoop* polling_loop = polling_thread_->message_loop();
252 polling_loop->PostTask(FROM_HERE,
253 base::Bind(&PollingThread::InitializePollingThread,
254 base::Unretained(polling_thread_),
255 factories_));
256 }
257
258 void ProviderImpl::DoNotify(const Orientation& orientation) {
259 DCHECK(MessageLoop::current() == creator_loop_);
260
261 last_notification_ = orientation;
262
263 typedef std::set<Observer*>::const_iterator Iterator;
264 for (Iterator i = observers_.begin(), e = observers_.end(); i != e; ++i)
hans 2012/07/30 12:56:40 nit: since you're touching this line anyway, feel
265 (*i)->OnOrientationUpdate(orientation);
266
267 if (orientation.is_empty()) {
268 // Notify observers about failure to provide data exactly once.
269 observers_.clear();
270 Stop();
271 }
272 }
273
209 } // namespace device_orientation 274 } // namespace device_orientation
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698