2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/page/NetworkStateNotifier.h"
29 #include "core/dom/CrossThreadTask.h"
30 #include "core/dom/ExecutionContext.h"
31 #include "core/page/Page.h"
32 #include "wtf/Assertions.h"
33 #include "wtf/Functional.h"
34 #include "wtf/MainThread.h"
35 #include "wtf/StdLibExtras.h"
36 #include "wtf/Threading.h"
40 NetworkStateNotifier& networkStateNotifier()
42 AtomicallyInitializedStatic(NetworkStateNotifier*, networkStateNotifier = new NetworkStateNotifier);
43 return *networkStateNotifier;
46 void NetworkStateNotifier::setOnLine(bool onLine)
48 ASSERT(isMainThread());
51 MutexLocker locker(m_mutex);
52 if (m_isOnLine == onLine)
58 Page::networkStateChanged(onLine);
61 void NetworkStateNotifier::setWebConnectionType(blink::WebConnectionType type)
63 ASSERT(isMainThread());
64 if (m_testUpdatesOnly)
67 setWebConnectionTypeImpl(type);
70 void NetworkStateNotifier::setWebConnectionTypeImpl(blink::WebConnectionType type)
72 ASSERT(isMainThread());
74 MutexLocker locker(m_mutex);
79 for (const auto& entry : m_observers) {
80 ExecutionContext* context = entry.key;
81 context->postTask(createCrossThreadTask(&NetworkStateNotifier::notifyObserversOnContext, this, AllowCrossThreadAccess(context), type));
85 void NetworkStateNotifier::addObserver(NetworkStateObserver* observer, ExecutionContext* context)
87 ASSERT(context->isContextThread());
90 MutexLocker locker(m_mutex);
91 ObserverListMap::AddResult result = m_observers.add(context, nullptr);
92 if (result.isNewEntry)
93 result.storedValue->value = adoptPtr(new ObserverList);
95 ASSERT(result.storedValue->value->observers.find(observer) == kNotFound);
96 result.storedValue->value->observers.append(observer);
99 void NetworkStateNotifier::removeObserver(NetworkStateObserver* observer, ExecutionContext* context)
101 ASSERT(context->isContextThread());
104 ObserverList* observerList = lockAndFindObserverList(context);
108 Vector<NetworkStateObserver*>& observers = observerList->observers;
109 size_t index = observers.find(observer);
110 if (index != kNotFound) {
111 observers[index] = 0;
112 observerList->zeroedObservers.append(index);
115 if (!observerList->iterating && !observerList->zeroedObservers.isEmpty())
116 collectZeroedObservers(observerList, context);
119 void NetworkStateNotifier::setTestUpdatesOnly(bool updatesOnly)
121 ASSERT(isMainThread());
122 m_testUpdatesOnly = updatesOnly;
125 void NetworkStateNotifier::setWebConnectionTypeForTest(blink::WebConnectionType type)
127 ASSERT(isMainThread());
128 ASSERT(m_testUpdatesOnly);
129 setWebConnectionTypeImpl(type);
132 void NetworkStateNotifier::notifyObserversOnContext(ExecutionContext* context, blink::WebConnectionType type)
134 ObserverList* observerList = lockAndFindObserverList(context);
136 // The context could have been removed before the notification task got to run.
140 ASSERT(context->isContextThread());
142 observerList->iterating = true;
144 for (size_t i = 0; i < observerList->observers.size(); ++i) {
145 // Observers removed during iteration are zeroed out, skip them.
146 if (observerList->observers[i])
147 observerList->observers[i]->connectionTypeChange(type);
150 observerList->iterating = false;
152 if (!observerList->zeroedObservers.isEmpty())
153 collectZeroedObservers(observerList, context);
156 NetworkStateNotifier::ObserverList* NetworkStateNotifier::lockAndFindObserverList(ExecutionContext* context)
158 MutexLocker locker(m_mutex);
159 ObserverListMap::iterator it = m_observers.find(context);
160 return it == m_observers.end() ? 0 : it->value.get();
163 void NetworkStateNotifier::collectZeroedObservers(ObserverList* list, ExecutionContext* context)
165 ASSERT(context->isContextThread());
166 ASSERT(!list->iterating);
168 // If any observers were removed during the iteration they will have
169 // 0 values, clean them up.
170 for (size_t i = 0; i < list->zeroedObservers.size(); ++i)
171 list->observers.remove(list->zeroedObservers[i]);
173 list->zeroedObservers.clear();
175 if (list->observers.isEmpty()) {
176 MutexLocker locker(m_mutex);
177 m_observers.remove(context); // deletes list