• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config.h"
27 #include "core/page/NetworkStateNotifier.h"
28 
29 #include "core/dom/ExecutionContext.h"
30 #include "core/page/Page.h"
31 #include "wtf/Assertions.h"
32 #include "wtf/Functional.h"
33 #include "wtf/MainThread.h"
34 #include "wtf/StdLibExtras.h"
35 #include "wtf/Threading.h"
36 
37 namespace WebCore {
38 
networkStateNotifier()39 NetworkStateNotifier& networkStateNotifier()
40 {
41     AtomicallyInitializedStatic(NetworkStateNotifier*, networkStateNotifier = new NetworkStateNotifier);
42     return *networkStateNotifier;
43 }
44 
setOnLine(bool onLine)45 void NetworkStateNotifier::setOnLine(bool onLine)
46 {
47     ASSERT(isMainThread());
48 
49     {
50         MutexLocker locker(m_mutex);
51         if (m_isOnLine == onLine)
52             return;
53 
54         m_isOnLine = onLine;
55     }
56 
57     Page::networkStateChanged(onLine);
58 }
59 
setWebConnectionType(blink::WebConnectionType type)60 void NetworkStateNotifier::setWebConnectionType(blink::WebConnectionType type)
61 {
62     ASSERT(isMainThread());
63     if (m_testUpdatesOnly)
64         return;
65 
66     setWebConnectionTypeImpl(type);
67 }
68 
setWebConnectionTypeImpl(blink::WebConnectionType type)69 void NetworkStateNotifier::setWebConnectionTypeImpl(blink::WebConnectionType type)
70 {
71     ASSERT(isMainThread());
72 
73     MutexLocker locker(m_mutex);
74     if (m_type == type)
75         return;
76     m_type = type;
77 
78     for (ObserverListMap::iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
79         ExecutionContext* context = it->key;
80         context->postTask(bind(&NetworkStateNotifier::notifyObserversOnContext, this, context, type));
81     }
82 }
83 
addObserver(NetworkStateObserver * observer,ExecutionContext * context)84 void NetworkStateNotifier::addObserver(NetworkStateObserver* observer, ExecutionContext* context)
85 {
86     ASSERT(context->isContextThread());
87     ASSERT(observer);
88 
89     MutexLocker locker(m_mutex);
90     ObserverListMap::AddResult result = m_observers.add(context, nullptr);
91     if (result.isNewEntry)
92         result.storedValue->value = adoptPtr(new ObserverList);
93 
94     ASSERT(result.storedValue->value->observers.find(observer) == kNotFound);
95     result.storedValue->value->observers.append(observer);
96 }
97 
removeObserver(NetworkStateObserver * observer,ExecutionContext * context)98 void NetworkStateNotifier::removeObserver(NetworkStateObserver* observer, ExecutionContext* context)
99 {
100     ASSERT(context->isContextThread());
101     ASSERT(observer);
102 
103     ObserverList* observerList = lockAndFindObserverList(context);
104     if (!observerList)
105         return;
106 
107     Vector<NetworkStateObserver*>& observers = observerList->observers;
108     size_t index = observers.find(observer);
109     if (index != kNotFound) {
110         observers[index] = 0;
111         observerList->zeroedObservers.append(index);
112     }
113 
114     if (!observerList->iterating && !observerList->zeroedObservers.isEmpty())
115         collectZeroedObservers(observerList, context);
116 }
117 
setTestUpdatesOnly(bool updatesOnly)118 void NetworkStateNotifier::setTestUpdatesOnly(bool updatesOnly)
119 {
120     ASSERT(isMainThread());
121     m_testUpdatesOnly = updatesOnly;
122 }
123 
setWebConnectionTypeForTest(blink::WebConnectionType type)124 void NetworkStateNotifier::setWebConnectionTypeForTest(blink::WebConnectionType type)
125 {
126     ASSERT(isMainThread());
127     ASSERT(m_testUpdatesOnly);
128     setWebConnectionTypeImpl(type);
129 }
130 
notifyObserversOnContext(ExecutionContext * context,blink::WebConnectionType type)131 void NetworkStateNotifier::notifyObserversOnContext(ExecutionContext* context, blink::WebConnectionType type)
132 {
133     ObserverList* observerList = lockAndFindObserverList(context);
134 
135     // The context could have been removed before the notification task got to run.
136     if (!observerList)
137         return;
138 
139     ASSERT(context->isContextThread());
140 
141     observerList->iterating = true;
142 
143     for (size_t i = 0; i < observerList->observers.size(); ++i) {
144         // Observers removed during iteration are zeroed out, skip them.
145         if (observerList->observers[i])
146             observerList->observers[i]->connectionTypeChange(type);
147     }
148 
149     observerList->iterating = false;
150 
151     if (!observerList->zeroedObservers.isEmpty())
152         collectZeroedObservers(observerList, context);
153 }
154 
lockAndFindObserverList(ExecutionContext * context)155 NetworkStateNotifier::ObserverList* NetworkStateNotifier::lockAndFindObserverList(ExecutionContext* context)
156 {
157     MutexLocker locker(m_mutex);
158     ObserverListMap::iterator it = m_observers.find(context);
159     return it == m_observers.end() ? 0 : it->value.get();
160 }
161 
collectZeroedObservers(ObserverList * list,ExecutionContext * context)162 void NetworkStateNotifier::collectZeroedObservers(ObserverList* list, ExecutionContext* context)
163 {
164     ASSERT(context->isContextThread());
165     ASSERT(!list->iterating);
166 
167     // If any observers were removed during the iteration they will have
168     // 0 values, clean them up.
169     for (size_t i = 0; i < list->zeroedObservers.size(); ++i)
170         list->observers.remove(list->zeroedObservers[i]);
171 
172     list->zeroedObservers.clear();
173 
174     if (list->observers.isEmpty()) {
175         MutexLocker locker(m_mutex);
176         m_observers.remove(context); // deletes list
177     }
178 }
179 
180 } // namespace WebCore
181