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