HostRecord.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /*
  2. * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``AS IS''
  14. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. * THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "HostRecord.h"
  27. #include "Logging.h"
  28. #include "NetworkConnectionToWebProcess.h"
  29. #include "NetworkProcess.h"
  30. #include "NetworkResourceLoadParameters.h"
  31. #include "NetworkResourceLoadScheduler.h"
  32. #include "NetworkResourceLoader.h"
  33. #include <wtf/MainThread.h>
  34. #if ENABLE(NETWORK_PROCESS)
  35. using namespace WebCore;
  36. namespace WebKit {
  37. HostRecord::HostRecord(const String& name, int maxRequestsInFlight)
  38. : m_name(name)
  39. , m_maxRequestsInFlight(maxRequestsInFlight)
  40. {
  41. }
  42. HostRecord::~HostRecord()
  43. {
  44. #ifndef NDEBUG
  45. ASSERT(m_loadersInProgress.isEmpty());
  46. for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++)
  47. ASSERT(m_loadersPending[p].isEmpty());
  48. #endif
  49. }
  50. void HostRecord::scheduleResourceLoader(PassRefPtr<NetworkResourceLoader> loader)
  51. {
  52. ASSERT(isMainThread());
  53. loader->setHostRecord(this);
  54. if (loader->isSynchronous())
  55. m_syncLoadersPending.append(loader);
  56. else
  57. m_loadersPending[loader->priority()].append(loader);
  58. }
  59. void HostRecord::addLoaderInProgress(NetworkResourceLoader* loader)
  60. {
  61. ASSERT(isMainThread());
  62. m_loadersInProgress.add(loader);
  63. loader->setHostRecord(this);
  64. }
  65. inline bool removeLoaderFromQueue(NetworkResourceLoader* loader, LoaderQueue& queue)
  66. {
  67. LoaderQueue::iterator end = queue.end();
  68. for (LoaderQueue::iterator it = queue.begin(); it != end; ++it) {
  69. if (it->get() == loader) {
  70. loader->setHostRecord(0);
  71. queue.remove(it);
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. void HostRecord::removeLoader(NetworkResourceLoader* loader)
  78. {
  79. ASSERT(isMainThread());
  80. // FIXME (NetworkProcess): Due to IPC race conditions, it's possible this HostRecord will be asked to remove the same loader twice.
  81. // It would be nice to know the loader has already been removed and treat it as a no-op.
  82. NetworkResourceLoaderSet::iterator i = m_loadersInProgress.find(loader);
  83. if (i != m_loadersInProgress.end()) {
  84. i->get()->setHostRecord(0);
  85. m_loadersInProgress.remove(i);
  86. return;
  87. }
  88. if (removeLoaderFromQueue(loader, m_syncLoadersPending))
  89. return;
  90. for (int priority = ResourceLoadPriorityHighest; priority >= ResourceLoadPriorityLowest; --priority) {
  91. if (removeLoaderFromQueue(loader, m_loadersPending[priority]))
  92. return;
  93. }
  94. }
  95. bool HostRecord::hasRequests() const
  96. {
  97. if (!m_loadersInProgress.isEmpty())
  98. return true;
  99. for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++) {
  100. if (!m_loadersPending[p].isEmpty())
  101. return true;
  102. }
  103. return false;
  104. }
  105. uint64_t HostRecord::pendingRequestCount() const
  106. {
  107. uint64_t count = 0;
  108. for (unsigned p = 0; p <= ResourceLoadPriorityHighest; p++)
  109. count += m_loadersPending[p].size();
  110. return count;
  111. }
  112. uint64_t HostRecord::activeLoadCount() const
  113. {
  114. return m_loadersInProgress.size();
  115. }
  116. void HostRecord::servePendingRequestsForQueue(LoaderQueue& queue, ResourceLoadPriority priority)
  117. {
  118. // We only enforce the connection limit for http(s) hosts, which are the only ones with names.
  119. bool shouldLimitRequests = !name().isNull();
  120. // For non-named hosts - everything but http(s) - we should only enforce the limit if the document
  121. // isn't done parsing and we don't know all stylesheets yet.
  122. // FIXME (NetworkProcess): The above comment about document parsing and stylesheets is a holdover
  123. // from the WebCore::ResourceLoadScheduler.
  124. // The behavior described was at one time important for WebCore's single threadedness.
  125. // It's possible that we don't care about it with the NetworkProcess.
  126. // We should either decide it's not important and change the above comment, or decide it is
  127. // still important and somehow account for it.
  128. // Very low priority loaders are only handled when no other loaders are in progress.
  129. if (shouldLimitRequests && priority == ResourceLoadPriorityVeryLow && !m_loadersInProgress.isEmpty())
  130. return;
  131. while (!queue.isEmpty()) {
  132. RefPtr<NetworkResourceLoader> loader = queue.first();
  133. ASSERT(loader->hostRecord() == this);
  134. // This request might be from WebProcess we've lost our connection to.
  135. // If so we should just skip it.
  136. if (!loader->connectionToWebProcess()) {
  137. removeLoader(loader.get());
  138. continue;
  139. }
  140. if (shouldLimitRequests && limitsRequests(priority, loader.get()))
  141. return;
  142. m_loadersInProgress.add(loader);
  143. queue.removeFirst();
  144. LOG(NetworkScheduling, "(NetworkProcess) HostRecord::servePendingRequestsForQueue - Starting load of %s\n", loader->request().url().string().utf8().data());
  145. loader->start();
  146. }
  147. }
  148. void HostRecord::servePendingRequests(ResourceLoadPriority minimumPriority)
  149. {
  150. LOG(NetworkScheduling, "(NetworkProcess) HostRecord::servePendingRequests Host name='%s'", name().utf8().data());
  151. // We serve synchronous requests before any other requests to improve responsiveness in any
  152. // WebProcess that is waiting on a synchronous load.
  153. servePendingRequestsForQueue(m_syncLoadersPending, ResourceLoadPriorityHighest);
  154. for (int priority = ResourceLoadPriorityHighest; priority >= minimumPriority; --priority)
  155. servePendingRequestsForQueue(m_loadersPending[priority], (ResourceLoadPriority)priority);
  156. }
  157. bool HostRecord::limitsRequests(ResourceLoadPriority priority, NetworkResourceLoader* loader) const
  158. {
  159. ASSERT(loader);
  160. ASSERT(loader->connectionToWebProcess());
  161. if (priority == ResourceLoadPriorityVeryLow && !m_loadersInProgress.isEmpty())
  162. return true;
  163. if (loader->connectionToWebProcess()->isSerialLoadingEnabled() && m_loadersInProgress.size() >= 1)
  164. return true;
  165. // If we're exactly at the limit for requests in flight, and this loader is asynchronous, then we're done serving new requests.
  166. // The synchronous loader exception handles the case where a sync XHR is made while 6 other requests are already in flight.
  167. if (m_loadersInProgress.size() == m_maxRequestsInFlight && !loader->isSynchronous())
  168. return true;
  169. // If we're already past the limit of the number of loaders in flight, we won't even serve new synchronous requests right now.
  170. if (m_loadersInProgress.size() > m_maxRequestsInFlight) {
  171. #ifndef NDEBUG
  172. // If we have more loaders in progress than we should, at least one of them had better be synchronous.
  173. NetworkResourceLoaderSet::iterator i = m_loadersInProgress.begin();
  174. NetworkResourceLoaderSet::iterator end = m_loadersInProgress.end();
  175. for (; i != end; ++i) {
  176. if (i->get()->isSynchronous())
  177. break;
  178. }
  179. ASSERT(i != end);
  180. #endif
  181. return true;
  182. }
  183. return false;
  184. }
  185. } // namespace WebKit
  186. #endif // ENABLE(NETWORK_PROCESS)