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

Side by Side Diff: third_party/WebKit/Source/core/page/NetworkStateNotifier.cpp

Issue 2710023006: Move NetworkStateNotifier from core (and web) into platform/network (Closed)
Patch Set: rebase Created 3 years, 9 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
(Empty)
1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "core/page/NetworkStateNotifier.h"
27
28 #include "platform/CrossThreadFunctional.h"
29 #include "wtf/Assertions.h"
30 #include "wtf/Functional.h"
31 #include "wtf/PtrUtil.h"
32 #include "wtf/StdLibExtras.h"
33 #include "wtf/Threading.h"
34
35 namespace blink {
36
37 template <>
38 struct CrossThreadCopier<NetworkStateNotifier::NetworkState>
39 : public CrossThreadCopierPassThrough<NetworkStateNotifier::NetworkState> {
40 STATIC_ONLY(CrossThreadCopier);
41 };
42
43 NetworkStateNotifier& networkStateNotifier() {
44 DEFINE_THREAD_SAFE_STATIC_LOCAL(NetworkStateNotifier, networkStateNotifier,
45 new NetworkStateNotifier);
46 return networkStateNotifier;
47 }
48
49 NetworkStateNotifier::ScopedNotifier::ScopedNotifier(
50 NetworkStateNotifier& notifier)
51 : m_notifier(notifier) {
52 DCHECK(isMainThread());
53 m_before =
54 m_notifier.m_hasOverride ? m_notifier.m_override : m_notifier.m_state;
55 }
56
57 NetworkStateNotifier::ScopedNotifier::~ScopedNotifier() {
58 DCHECK(isMainThread());
59 const NetworkState& after =
60 m_notifier.m_hasOverride ? m_notifier.m_override : m_notifier.m_state;
61 if ((after.type != m_before.type ||
62 after.maxBandwidthMbps != m_before.maxBandwidthMbps) &&
63 m_before.connectionInitialized) {
64 m_notifier.notifyObservers(m_notifier.m_connectionObservers,
65 ObserverType::CONNECTION_TYPE, after);
66 }
67 if (after.onLine != m_before.onLine && m_before.onLineInitialized) {
68 m_notifier.notifyObservers(m_notifier.m_onLineStateObservers,
69 ObserverType::ONLINE_STATE, after);
70 }
71 }
72
73 void NetworkStateNotifier::setOnLine(bool onLine) {
74 DCHECK(isMainThread());
75 ScopedNotifier notifier(*this);
76 {
77 MutexLocker locker(m_mutex);
78 m_state.onLineInitialized = true;
79 m_state.onLine = onLine;
80 }
81 }
82
83 void NetworkStateNotifier::setWebConnection(WebConnectionType type,
84 double maxBandwidthMbps) {
85 DCHECK(isMainThread());
86 ScopedNotifier notifier(*this);
87 {
88 MutexLocker locker(m_mutex);
89 m_state.connectionInitialized = true;
90 m_state.type = type;
91 m_state.maxBandwidthMbps = maxBandwidthMbps;
92 }
93 }
94
95 void NetworkStateNotifier::addConnectionObserver(
96 NetworkStateObserver* observer,
97 PassRefPtr<WebTaskRunner> taskRunner) {
98 addObserver(m_connectionObservers, observer, std::move(taskRunner));
99 }
100
101 void NetworkStateNotifier::addOnLineObserver(
102 NetworkStateObserver* observer,
103 PassRefPtr<WebTaskRunner> taskRunner) {
104 addObserver(m_onLineStateObservers, observer, std::move(taskRunner));
105 }
106
107 void NetworkStateNotifier::removeConnectionObserver(
108 NetworkStateObserver* observer,
109 PassRefPtr<WebTaskRunner> taskRunner) {
110 removeObserver(m_connectionObservers, observer, std::move(taskRunner));
111 }
112
113 void NetworkStateNotifier::removeOnLineObserver(
114 NetworkStateObserver* observer,
115 PassRefPtr<WebTaskRunner> taskRunner) {
116 removeObserver(m_onLineStateObservers, observer, std::move(taskRunner));
117 }
118
119 void NetworkStateNotifier::setOverride(bool onLine,
120 WebConnectionType type,
121 double maxBandwidthMbps) {
122 DCHECK(isMainThread());
123 ScopedNotifier notifier(*this);
124 {
125 MutexLocker locker(m_mutex);
126 m_hasOverride = true;
127 m_override.onLineInitialized = true;
128 m_override.onLine = onLine;
129 m_override.connectionInitialized = true;
130 m_override.type = type;
131 m_override.maxBandwidthMbps = maxBandwidthMbps;
132 }
133 }
134
135 void NetworkStateNotifier::clearOverride() {
136 DCHECK(isMainThread());
137 ScopedNotifier notifier(*this);
138 {
139 MutexLocker locker(m_mutex);
140 m_hasOverride = false;
141 }
142 }
143
144 void NetworkStateNotifier::notifyObservers(ObserverListMap& map,
145 ObserverType type,
146 const NetworkState& state) {
147 DCHECK(isMainThread());
148 MutexLocker locker(m_mutex);
149 for (const auto& entry : map) {
150 RefPtr<WebTaskRunner> taskRunner = entry.key;
151 taskRunner->postTask(
152 BLINK_FROM_HERE,
153 crossThreadBind(&NetworkStateNotifier::notifyObserversOnTaskRunner,
154 crossThreadUnretained(this),
155 crossThreadUnretained(&map), type, taskRunner, state));
156 }
157 }
158
159 void NetworkStateNotifier::notifyObserversOnTaskRunner(
160 ObserverListMap* map,
161 ObserverType type,
162 PassRefPtr<WebTaskRunner> passTaskRunner,
163 const NetworkState& state) {
164 RefPtr<WebTaskRunner> taskRunner = passTaskRunner;
165 ObserverList* observerList = lockAndFindObserverList(*map, taskRunner);
166
167 // The context could have been removed before the notification task got to
168 // run.
169 if (!observerList)
170 return;
171
172 DCHECK(taskRunner->runsTasksOnCurrentThread());
173
174 observerList->iterating = true;
175
176 for (size_t i = 0; i < observerList->observers.size(); ++i) {
177 // Observers removed during iteration are zeroed out, skip them.
178 if (!observerList->observers[i])
179 continue;
180 switch (type) {
181 case ObserverType::ONLINE_STATE:
182 observerList->observers[i]->onLineStateChange(state.onLine);
183 continue;
184 case ObserverType::CONNECTION_TYPE:
185 observerList->observers[i]->connectionChange(state.type,
186 state.maxBandwidthMbps);
187 continue;
188 }
189 NOTREACHED();
190 }
191
192 observerList->iterating = false;
193
194 if (!observerList->zeroedObservers.isEmpty())
195 collectZeroedObservers(*map, observerList, taskRunner);
196 }
197
198 void NetworkStateNotifier::addObserver(ObserverListMap& map,
199 NetworkStateObserver* observer,
200 PassRefPtr<WebTaskRunner> taskRunner) {
201 DCHECK(taskRunner->runsTasksOnCurrentThread());
202 DCHECK(observer);
203
204 MutexLocker locker(m_mutex);
205 ObserverListMap::AddResult result =
206 map.insert(std::move(taskRunner), nullptr);
207 if (result.isNewEntry)
208 result.storedValue->value = WTF::makeUnique<ObserverList>();
209
210 DCHECK(result.storedValue->value->observers.find(observer) == kNotFound);
211 result.storedValue->value->observers.push_back(observer);
212 }
213
214 void NetworkStateNotifier::removeObserver(
215 ObserverListMap& map,
216 NetworkStateObserver* observer,
217 PassRefPtr<WebTaskRunner> passTaskRunner) {
218 RefPtr<WebTaskRunner> taskRunner = passTaskRunner;
219 DCHECK(taskRunner->runsTasksOnCurrentThread());
220 DCHECK(observer);
221
222 ObserverList* observerList = lockAndFindObserverList(map, taskRunner);
223 if (!observerList)
224 return;
225
226 Vector<NetworkStateObserver*>& observers = observerList->observers;
227 size_t index = observers.find(observer);
228 if (index != kNotFound) {
229 observers[index] = 0;
230 observerList->zeroedObservers.push_back(index);
231 }
232
233 if (!observerList->iterating && !observerList->zeroedObservers.isEmpty())
234 collectZeroedObservers(map, observerList, taskRunner);
235 }
236
237 NetworkStateNotifier::ObserverList*
238 NetworkStateNotifier::lockAndFindObserverList(
239 ObserverListMap& map,
240 PassRefPtr<WebTaskRunner> taskRunner) {
241 MutexLocker locker(m_mutex);
242 ObserverListMap::iterator it = map.find(taskRunner);
243 return it == map.end() ? nullptr : it->value.get();
244 }
245
246 void NetworkStateNotifier::collectZeroedObservers(
247 ObserverListMap& map,
248 ObserverList* list,
249 PassRefPtr<WebTaskRunner> taskRunner) {
250 DCHECK(taskRunner->runsTasksOnCurrentThread());
251 DCHECK(!list->iterating);
252
253 // If any observers were removed during the iteration they will have
254 // 0 values, clean them up.
255 for (size_t i = 0; i < list->zeroedObservers.size(); ++i)
256 list->observers.remove(list->zeroedObservers[i]);
257
258 list->zeroedObservers.clear();
259
260 if (list->observers.isEmpty()) {
261 MutexLocker locker(m_mutex);
262 map.erase(taskRunner); // deletes list
263 }
264 }
265
266 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698