Home | History | Annotate | Download | only in page
      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 
     39 NetworkStateNotifier& networkStateNotifier()
     40 {
     41     AtomicallyInitializedStatic(NetworkStateNotifier*, networkStateNotifier = new NetworkStateNotifier);
     42     return *networkStateNotifier;
     43 }
     44 
     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 
     60 void NetworkStateNotifier::setWebConnectionType(blink::WebConnectionType type)
     61 {
     62     ASSERT(isMainThread());
     63     if (m_testUpdatesOnly)
     64         return;
     65 
     66     setWebConnectionTypeImpl(type);
     67 }
     68 
     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 
     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 
     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 
    118 void NetworkStateNotifier::setTestUpdatesOnly(bool updatesOnly)
    119 {
    120     ASSERT(isMainThread());
    121     m_testUpdatesOnly = updatesOnly;
    122 }
    123 
    124 void NetworkStateNotifier::setWebConnectionTypeForTest(blink::WebConnectionType type)
    125 {
    126     ASSERT(isMainThread());
    127     ASSERT(m_testUpdatesOnly);
    128     setWebConnectionTypeImpl(type);
    129 }
    130 
    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 
    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 
    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