| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/socket/client_socket_pool_base.h" | 5 #include "net/socket/client_socket_pool_base.h" |
| 6 | 6 |
| 7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
| 8 #include "base/format_macros.h" | 8 #include "base/format_macros.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/stats_counters.h" | 10 #include "base/stats_counters.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper( | 110 ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper( |
| 111 int max_sockets, | 111 int max_sockets, |
| 112 int max_sockets_per_group, | 112 int max_sockets_per_group, |
| 113 base::TimeDelta unused_idle_socket_timeout, | 113 base::TimeDelta unused_idle_socket_timeout, |
| 114 base::TimeDelta used_idle_socket_timeout, | 114 base::TimeDelta used_idle_socket_timeout, |
| 115 ConnectJobFactory* connect_job_factory, | 115 ConnectJobFactory* connect_job_factory, |
| 116 NetworkChangeNotifier* network_change_notifier) | 116 NetworkChangeNotifier* network_change_notifier) |
| 117 : idle_socket_count_(0), | 117 : idle_socket_count_(0), |
| 118 connecting_socket_count_(0), | 118 connecting_socket_count_(0), |
| 119 handed_out_socket_count_(0), | 119 handed_out_socket_count_(0), |
| 120 num_releasing_sockets_(0), | |
| 121 max_sockets_(max_sockets), | 120 max_sockets_(max_sockets), |
| 122 max_sockets_per_group_(max_sockets_per_group), | 121 max_sockets_per_group_(max_sockets_per_group), |
| 123 unused_idle_socket_timeout_(unused_idle_socket_timeout), | 122 unused_idle_socket_timeout_(unused_idle_socket_timeout), |
| 124 used_idle_socket_timeout_(used_idle_socket_timeout), | 123 used_idle_socket_timeout_(used_idle_socket_timeout), |
| 125 may_have_stalled_group_(false), | 124 may_have_stalled_group_(false), |
| 126 connect_job_factory_(connect_job_factory), | 125 connect_job_factory_(connect_job_factory), |
| 127 network_change_notifier_(network_change_notifier), | 126 network_change_notifier_(network_change_notifier), |
| 128 backup_jobs_enabled_(false), | 127 backup_jobs_enabled_(false), |
| 129 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { | 128 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { |
| 130 DCHECK_LE(0, max_sockets_per_group); | 129 DCHECK_LE(0, max_sockets_per_group); |
| (...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 } | 351 } |
| 353 return; | 352 return; |
| 354 } | 353 } |
| 355 } | 354 } |
| 356 } | 355 } |
| 357 | 356 |
| 358 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name, | 357 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name, |
| 359 ClientSocket* socket) { | 358 ClientSocket* socket) { |
| 360 Group& group = group_map_[group_name]; | 359 Group& group = group_map_[group_name]; |
| 361 group.num_releasing_sockets++; | 360 group.num_releasing_sockets++; |
| 362 num_releasing_sockets_++; | |
| 363 DCHECK_LE(group.num_releasing_sockets, group.active_socket_count); | 361 DCHECK_LE(group.num_releasing_sockets, group.active_socket_count); |
| 364 // Run this asynchronously to allow the caller to finish before we let | 362 // Run this asynchronously to allow the caller to finish before we let |
| 365 // another to begin doing work. This also avoids nasty recursion issues. | 363 // another to begin doing work. This also avoids nasty recursion issues. |
| 366 // NOTE: We cannot refer to the handle argument after this method returns. | 364 // NOTE: We cannot refer to the handle argument after this method returns. |
| 367 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | 365 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
| 368 this, &ClientSocketPoolBaseHelper::DoReleaseSocket, group_name, socket)); | 366 this, &ClientSocketPoolBaseHelper::DoReleaseSocket, group_name, socket)); |
| 369 } | 367 } |
| 370 | 368 |
| 371 void ClientSocketPoolBaseHelper::CloseIdleSockets() { | 369 void ClientSocketPoolBaseHelper::CloseIdleSockets() { |
| 372 CleanupIdleSockets(true); | 370 CleanupIdleSockets(true); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 477 | 475 |
| 478 group.num_releasing_sockets--; | 476 group.num_releasing_sockets--; |
| 479 DCHECK_GE(group.num_releasing_sockets, 0); | 477 DCHECK_GE(group.num_releasing_sockets, 0); |
| 480 | 478 |
| 481 CHECK_GT(handed_out_socket_count_, 0); | 479 CHECK_GT(handed_out_socket_count_, 0); |
| 482 handed_out_socket_count_--; | 480 handed_out_socket_count_--; |
| 483 | 481 |
| 484 CHECK_GT(group.active_socket_count, 0); | 482 CHECK_GT(group.active_socket_count, 0); |
| 485 group.active_socket_count--; | 483 group.active_socket_count--; |
| 486 | 484 |
| 487 CHECK_GT(num_releasing_sockets_, 0); | |
| 488 num_releasing_sockets_--; | |
| 489 | |
| 490 const bool can_reuse = socket->IsConnectedAndIdle(); | 485 const bool can_reuse = socket->IsConnectedAndIdle(); |
| 491 if (can_reuse) { | 486 if (can_reuse) { |
| 492 AddIdleSocket(socket, true /* used socket */, &group); | 487 AddIdleSocket(socket, true /* used socket */, &group); |
| 493 } else { | 488 } else { |
| 494 delete socket; | 489 delete socket; |
| 495 } | 490 } |
| 496 | 491 |
| 492 OnAvailableSocketSlot(group_name, &group); |
| 493 |
| 497 // If there are no more releasing sockets, then we might have to process | 494 // If there are no more releasing sockets, then we might have to process |
| 498 // multiple available socket slots, since we stalled their processing until | 495 // multiple available socket slots, since we stalled their processing until |
| 499 // all sockets have been released. Note that ProcessPendingRequest() will | 496 // all sockets have been released. |
| 500 // invoke user callbacks, so |num_releasing_sockets_| may change. | 497 i = group_map_.find(group_name); |
| 501 // | 498 if (i == group_map_.end() || i->second.num_releasing_sockets > 0) |
| 502 // This code has been known to infinite loop. Set a counter and CHECK to make | 499 return; |
| 503 // sure it doesn't get ridiculously high. | |
| 504 | 500 |
| 505 int iterations = 0; | 501 while (true) { |
| 506 while (num_releasing_sockets_ == 0) { | 502 // We can't activate more sockets since we're already at our global limit. |
| 507 CHECK_LT(iterations, 100000) << "Probably stuck in an infinite loop."; | 503 if (ReachedMaxSocketsLimit()) |
| 508 std::string top_group_name; | 504 return; |
| 509 Group* top_group = NULL; | |
| 510 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); | |
| 511 if (stalled_group_count >= 1) { | |
| 512 if (ReachedMaxSocketsLimit()) { | |
| 513 // We can't activate more sockets since we're already at our global | |
| 514 // limit. | |
| 515 may_have_stalled_group_ = true; | |
| 516 return; | |
| 517 } | |
| 518 | 505 |
| 519 ProcessPendingRequest(top_group_name, top_group); | 506 // |group| might now be deleted. |
| 520 } else { | 507 i = group_map_.find(group_name); |
| 521 may_have_stalled_group_ = false; | 508 if (i == group_map_.end()) |
| 522 return; | 509 return; |
| 523 } | |
| 524 | 510 |
| 525 iterations++; | 511 group = i->second; |
| 512 |
| 513 // If we already have enough ConnectJobs to satisfy the pending requests, |
| 514 // don't bother starting up more. |
| 515 if (group.pending_requests.size() <= group.jobs.size()) |
| 516 return; |
| 517 |
| 518 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) |
| 519 return; |
| 520 |
| 521 OnAvailableSocketSlot(group_name, &group); |
| 526 } | 522 } |
| 527 } | 523 } |
| 528 | 524 |
| 529 // Search for the highest priority pending request, amongst the groups that | 525 // Search for the highest priority pending request, amongst the groups that |
| 530 // are not at the |max_sockets_per_group_| limit. Note: for requests with | 526 // are not at the |max_sockets_per_group_| limit. Note: for requests with |
| 531 // the same priority, the winner is based on group hash ordering (and not | 527 // the same priority, the winner is based on group hash ordering (and not |
| 532 // insertion order). | 528 // insertion order). |
| 533 int ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group, | 529 int ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group, |
| 534 std::string* group_name) { | 530 std::string* group_name) { |
| 535 Group* top_group = NULL; | 531 Group* top_group = NULL; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 OnAvailableSocketSlot(group_name, &group); | 633 OnAvailableSocketSlot(group_name, &group); |
| 638 } | 634 } |
| 639 } | 635 } |
| 640 | 636 |
| 641 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( | 637 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( |
| 642 const std::string& group_name, Group* group) { | 638 const std::string& group_name, Group* group) { |
| 643 if (may_have_stalled_group_) { | 639 if (may_have_stalled_group_) { |
| 644 std::string top_group_name; | 640 std::string top_group_name; |
| 645 Group* top_group = NULL; | 641 Group* top_group = NULL; |
| 646 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); | 642 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); |
| 647 if (stalled_group_count <= 1 && top_group->num_releasing_sockets == 0) | 643 if (stalled_group_count <= 1) |
| 648 may_have_stalled_group_ = false; | 644 may_have_stalled_group_ = false; |
| 649 if (stalled_group_count >= 1) | 645 if (stalled_group_count >= 1) |
| 650 ProcessPendingRequest(top_group_name, top_group); | 646 ProcessPendingRequest(top_group_name, top_group); |
| 651 } else if (!group->pending_requests.empty()) { | 647 } else if (!group->pending_requests.empty()) { |
| 652 ProcessPendingRequest(group_name, group); | 648 ProcessPendingRequest(group_name, group); |
| 653 // |group| may no longer be valid after this point. Be careful not to | 649 // |group| may no longer be valid after this point. Be careful not to |
| 654 // access it again. | 650 // access it again. |
| 655 } else if (group->IsEmpty()) { | 651 } else if (group->IsEmpty()) { |
| 656 // Delete |group| if no longer needed. |group| will no longer be valid. | 652 // Delete |group| if no longer needed. |group| will no longer be valid. |
| 657 group_map_.erase(group_name); | 653 group_map_.erase(group_name); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 DCHECK_LE(total, max_sockets_); | 736 DCHECK_LE(total, max_sockets_); |
| 741 if (total < max_sockets_) | 737 if (total < max_sockets_) |
| 742 return false; | 738 return false; |
| 743 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; | 739 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; |
| 744 return true; | 740 return true; |
| 745 } | 741 } |
| 746 | 742 |
| 747 } // namespace internal | 743 } // namespace internal |
| 748 | 744 |
| 749 } // namespace net | 745 } // namespace net |
| OLD | NEW |