summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/socket/client_socket_pool_base.cc31
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc41
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