| Index: net/socket/client_socket_pool_base.cc | 
| =================================================================== | 
| --- net/socket/client_socket_pool_base.cc	(revision 219027) | 
| +++ net/socket/client_socket_pool_base.cc	(working copy) | 
| @@ -165,6 +165,7 @@ | 
| ClientSocketPoolBaseHelper::Request::~Request() {} | 
|  | 
| ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper( | 
| +    HigherLayeredPool* pool, | 
| int max_sockets, | 
| int max_sockets_per_group, | 
| base::TimeDelta unused_idle_socket_timeout, | 
| @@ -181,6 +182,7 @@ | 
| connect_job_factory_(connect_job_factory), | 
| connect_backup_jobs_enabled_(false), | 
| pool_generation_number_(0), | 
| +      pool_(pool), | 
| weak_factory_(this) { | 
| DCHECK_LE(0, max_sockets_per_group); | 
| DCHECK_LE(max_sockets_per_group, max_sockets); | 
| @@ -196,9 +198,16 @@ | 
| DCHECK(group_map_.empty()); | 
| DCHECK(pending_callback_map_.empty()); | 
| DCHECK_EQ(0, connecting_socket_count_); | 
| -  CHECK(higher_layer_pools_.empty()); | 
| +  CHECK(higher_pools_.empty()); | 
|  | 
| NetworkChangeNotifier::RemoveIPAddressObserver(this); | 
| + | 
| +  // Remove from lower layer pools. | 
| +  for (std::set<LowerLayeredPool*>::iterator it = lower_pools_.begin(); | 
| +       it != lower_pools_.end(); | 
| +       ++it) { | 
| +    (*it)->RemoveHigherLayeredPool(pool_); | 
| +  } | 
| } | 
|  | 
| ClientSocketPoolBaseHelper::CallbackResultPair::CallbackResultPair() | 
| @@ -238,18 +247,56 @@ | 
| return req; | 
| } | 
|  | 
| -void ClientSocketPoolBaseHelper::AddLayeredPool(LayeredPool* pool) { | 
| -  CHECK(pool); | 
| -  CHECK(!ContainsKey(higher_layer_pools_, pool)); | 
| -  higher_layer_pools_.insert(pool); | 
| +bool ClientSocketPoolBaseHelper::IsStalled() const { | 
| +  // If a lower layer pool is stalled, consider |this| stalled as well. | 
| +  for (std::set<LowerLayeredPool*>::const_iterator it = lower_pools_.begin(); | 
| +       it != lower_pools_.end(); | 
| +       ++it) { | 
| +    if ((*it)->IsStalled()) | 
| +      return true; | 
| +  } | 
| + | 
| +  // If fewer than |max_sockets_| are in use, then clearly |this| is not | 
| +  // stalled. | 
| +  if ((handed_out_socket_count_ + connecting_socket_count_) < max_sockets_) | 
| +    return false; | 
| +  // So in order to be stalled, |this| must be using at least |max_sockets_| AND | 
| +  // |this| must have a request that is actually stalled on the global socket | 
| +  // limit.  To find such a request, look for a group that has more requests | 
| +  // than jobs AND where the number of sockets is less than | 
| +  // |max_sockets_per_group_|.  (If the number of sockets is equal to | 
| +  // |max_sockets_per_group_|, then the request is stalled on the group limit, | 
| +  // which does not count.) | 
| +  for (GroupMap::const_iterator it = group_map_.begin(); | 
| +       it != group_map_.end(); ++it) { | 
| +    if (it->second->IsStalledOnPoolMaxSockets(max_sockets_per_group_)) | 
| +      return true; | 
| +  } | 
| +  return false; | 
| } | 
|  | 
| -void ClientSocketPoolBaseHelper::RemoveLayeredPool(LayeredPool* pool) { | 
| -  CHECK(pool); | 
| -  CHECK(ContainsKey(higher_layer_pools_, pool)); | 
| -  higher_layer_pools_.erase(pool); | 
| +void ClientSocketPoolBaseHelper::AddLowerLayeredPool( | 
| +    LowerLayeredPool* lower_pool) { | 
| +  DCHECK(pool_); | 
| +  CHECK(!ContainsKey(lower_pools_, lower_pool)); | 
| +  lower_pools_.insert(lower_pool); | 
| +  lower_pool->AddHigherLayeredPool(pool_); | 
| } | 
|  | 
| +void ClientSocketPoolBaseHelper::AddHigherLayeredPool( | 
| +    HigherLayeredPool* higher_pool) { | 
| +  CHECK(higher_pool); | 
| +  CHECK(!ContainsKey(higher_pools_, higher_pool)); | 
| +  higher_pools_.insert(higher_pool); | 
| +} | 
| + | 
| +void ClientSocketPoolBaseHelper::RemoveHigherLayeredPool( | 
| +    HigherLayeredPool* higher_pool) { | 
| +  CHECK(higher_pool); | 
| +  CHECK(ContainsKey(higher_pools_, higher_pool)); | 
| +  higher_pools_.erase(higher_pool); | 
| +} | 
| + | 
| int ClientSocketPoolBaseHelper::RequestSocket( | 
| const std::string& group_name, | 
| const Request* request) { | 
| @@ -790,8 +837,18 @@ | 
| // If we have idle sockets, see if we can give one to the top-stalled group. | 
| std::string top_group_name; | 
| Group* top_group = NULL; | 
| -  if (!FindTopStalledGroup(&top_group, &top_group_name)) | 
| +  if (!FindTopStalledGroup(&top_group, &top_group_name)) { | 
| +    // There may still be a stalled group in a lower level pool. | 
| +    for (std::set<LowerLayeredPool*>::iterator it = lower_pools_.begin(); | 
| +         it != lower_pools_.end(); | 
| +         ++it) { | 
| +       if ((*it)->IsStalled()) { | 
| +         CloseOneIdleSocket(); | 
| +         break; | 
| +       } | 
| +    } | 
| return; | 
| +  } | 
|  | 
| if (ReachedMaxSocketsLimit()) { | 
| if (idle_socket_count() > 0) { | 
| @@ -924,25 +981,6 @@ | 
| CancelAllRequestsWithError(error); | 
| } | 
|  | 
| -bool ClientSocketPoolBaseHelper::IsStalled() const { | 
| -  // If we are not using |max_sockets_|, then clearly we are not stalled | 
| -  if ((handed_out_socket_count_ + connecting_socket_count_) < max_sockets_) | 
| -    return false; | 
| -  // So in order to be stalled we need to be using |max_sockets_| AND | 
| -  // we need to have a request that is actually stalled on the global | 
| -  // socket limit.  To find such a request, we look for a group that | 
| -  // a has more requests that jobs AND where the number of jobs is less | 
| -  // than |max_sockets_per_group_|.  (If the number of jobs is equal to | 
| -  // |max_sockets_per_group_|, then the request is stalled on the group, | 
| -  // which does not count.) | 
| -  for (GroupMap::const_iterator it = group_map_.begin(); | 
| -       it != group_map_.end(); ++it) { | 
| -    if (it->second->IsStalledOnPoolMaxSockets(max_sockets_per_group_)) | 
| -      return true; | 
| -  } | 
| -  return false; | 
| -} | 
| - | 
| void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job, | 
| Group* group) { | 
| CHECK_GT(connecting_socket_count_, 0); | 
| @@ -1108,12 +1146,12 @@ | 
| return false; | 
| } | 
|  | 
| -bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInLayeredPool() { | 
| +bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInHigherLayeredPool() { | 
| // This pool doesn't have any idle sockets. It's possible that a pool at a | 
| // higher layer is holding one of this sockets active, but it's actually idle. | 
| // Query the higher layers. | 
| -  for (std::set<LayeredPool*>::const_iterator it = higher_layer_pools_.begin(); | 
| -       it != higher_layer_pools_.end(); ++it) { | 
| +  for (std::set<HigherLayeredPool*>::const_iterator it = higher_pools_.begin(); | 
| +       it != higher_pools_.end(); ++it) { | 
| if ((*it)->CloseOneIdleConnection()) | 
| return true; | 
| } | 
| @@ -1149,7 +1187,7 @@ | 
| while (IsStalled()) { | 
| // Closing a socket will result in calling back into |this| to use the freed | 
| // socket slot, so nothing else is needed. | 
| -    if (!CloseOneIdleConnectionInLayeredPool()) | 
| +    if (!CloseOneIdleConnectionInHigherLayeredPool()) | 
| return; | 
| } | 
| } | 
|  |