diff options
-rw-r--r-- | net/socket/client_socket_pool_base.cc | 31 | ||||
-rw-r--r-- | net/socket/client_socket_pool_base_unittest.cc | 41 |
2 files changed, 72 insertions, 0 deletions
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc index 9b14f4b..24c2dc6 100644 --- a/net/socket/client_socket_pool_base.cc +++ b/net/socket/client_socket_pool_base.cc @@ -395,7 +395,38 @@ void ClientSocketPoolBaseHelper::DoReleaseSocket(const std::string& group_name, delete socket; } + const bool more_releasing_sockets = group.num_releasing_sockets > 0; + OnAvailableSocketSlot(group_name, &group); + + // If there are no more releasing sockets, then we might have to process + // multiple available socket slots, since we stalled their processing until + // all sockets have been released. + if (more_releasing_sockets) + return; + + while (true) { + // We can't activate more sockets since we're already at our global limit. + if (ReachedMaxSocketsLimit()) + return; + + // |group| might now be deleted. + i = group_map_.find(group_name); + if (i == group_map_.end()) + return; + + group = i->second; + + // If we already have enough ConnectJobs to satisfy the pending requests, + // don't bother starting up more. + if (group.pending_requests.size() <= group.jobs.size()) + return; + + if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) + return; + + OnAvailableSocketSlot(group_name, &group); + } } // Search for the highest priority pending request, amongst the groups that diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc index d4c510f8..9f875ad 100644 --- a/net/socket/client_socket_pool_base_unittest.cc +++ b/net/socket/client_socket_pool_base_unittest.cc @@ -1389,6 +1389,47 @@ TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) { EXPECT_TRUE(req.handle()->is_reused()); } +// Make sure that we process all pending requests even when we're stalling +// because of multiple releasing disconnected sockets. +TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) { + CreatePoolWithIdleTimeouts( + kDefaultMaxSockets, kDefaultMaxSocketsPerGroup, + base::TimeDelta(), // Time out unused sockets immediately. + base::TimeDelta::FromDays(1)); // Don't time out used sockets. + + connect_job_factory_->set_job_type(TestConnectJob::kMockJob); + + // Startup 4 connect jobs. Two of them will be pending. + + TestSocketRequest req(&request_order_, &completion_count_); + int rv = InitHandle(req.handle(), "a", LOWEST, &req, pool_.get(), NULL); + EXPECT_EQ(OK, rv); + + TestSocketRequest req2(&request_order_, &completion_count_); + rv = InitHandle(req2.handle(), "a", LOWEST, &req2, pool_.get(), NULL); + EXPECT_EQ(OK, rv); + + TestSocketRequest req3(&request_order_, &completion_count_); + rv = InitHandle(req3.handle(), "a", LOWEST, &req3, pool_.get(), NULL); + EXPECT_EQ(ERR_IO_PENDING, rv); + + TestSocketRequest req4(&request_order_, &completion_count_); + rv = InitHandle(req4.handle(), "a", LOWEST, &req4, pool_.get(), NULL); + EXPECT_EQ(ERR_IO_PENDING, rv); + + // Release two disconnected sockets. + + req.handle()->socket()->Disconnect(); + req.handle()->Reset(); + req2.handle()->socket()->Disconnect(); + req2.handle()->Reset(); + + EXPECT_EQ(OK, req3.WaitForResult()); + EXPECT_FALSE(req3.handle()->is_reused()); + EXPECT_EQ(OK, req4.WaitForResult()); + EXPECT_FALSE(req4.handle()->is_reused()); +} + } // namespace } // namespace net |