1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/socket/websocket_endpoint_lock_manager.h" 6 7 #include <utility> 8 9 #include "base/logging.h" 10 #include "net/base/net_errors.h" 11 #include "net/base/net_log.h" 12 13 namespace net { 14 ~Waiter()15WebSocketEndpointLockManager::Waiter::~Waiter() { 16 if (next()) { 17 DCHECK(previous()); 18 RemoveFromList(); 19 } 20 } 21 GetInstance()22WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { 23 return Singleton<WebSocketEndpointLockManager>::get(); 24 } 25 LockEndpoint(const IPEndPoint & endpoint,Waiter * waiter)26int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint, 27 Waiter* waiter) { 28 LockInfoMap::value_type insert_value(endpoint, LockInfo()); 29 std::pair<LockInfoMap::iterator, bool> rv = 30 lock_info_map_.insert(insert_value); 31 LockInfo& lock_info_in_map = rv.first->second; 32 if (rv.second) { 33 DVLOG(3) << "Locking endpoint " << endpoint.ToString(); 34 lock_info_in_map.queue.reset(new LockInfo::WaiterQueue); 35 return OK; 36 } 37 DVLOG(3) << "Waiting for endpoint " << endpoint.ToString(); 38 lock_info_in_map.queue->Append(waiter); 39 return ERR_IO_PENDING; 40 } 41 RememberSocket(StreamSocket * socket,const IPEndPoint & endpoint)42void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket, 43 const IPEndPoint& endpoint) { 44 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); 45 CHECK(lock_info_it != lock_info_map_.end()); 46 bool inserted = 47 socket_lock_info_map_.insert(SocketLockInfoMap::value_type( 48 socket, lock_info_it)).second; 49 DCHECK(inserted); 50 DCHECK(!lock_info_it->second.socket); 51 lock_info_it->second.socket = socket; 52 DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for " 53 << endpoint.ToString() << " (" << socket_lock_info_map_.size() 54 << " socket(s) remembered)"; 55 } 56 UnlockSocket(StreamSocket * socket)57void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) { 58 SocketLockInfoMap::iterator socket_it = socket_lock_info_map_.find(socket); 59 if (socket_it == socket_lock_info_map_.end()) 60 return; 61 62 LockInfoMap::iterator lock_info_it = socket_it->second; 63 64 DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " 65 << lock_info_it->first.ToString() << " (" 66 << socket_lock_info_map_.size() << " socket(s) left)"; 67 socket_lock_info_map_.erase(socket_it); 68 DCHECK(socket == lock_info_it->second.socket); 69 lock_info_it->second.socket = NULL; 70 UnlockEndpointByIterator(lock_info_it); 71 } 72 UnlockEndpoint(const IPEndPoint & endpoint)73void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { 74 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); 75 if (lock_info_it == lock_info_map_.end()) 76 return; 77 78 UnlockEndpointByIterator(lock_info_it); 79 } 80 IsEmpty() const81bool WebSocketEndpointLockManager::IsEmpty() const { 82 return lock_info_map_.empty() && socket_lock_info_map_.empty(); 83 } 84 LockInfo()85WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {} ~LockInfo()86WebSocketEndpointLockManager::LockInfo::~LockInfo() { 87 DCHECK(!socket); 88 } 89 LockInfo(const LockInfo & rhs)90WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs) 91 : socket(rhs.socket) { 92 DCHECK(!rhs.queue); 93 } 94 WebSocketEndpointLockManager()95WebSocketEndpointLockManager::WebSocketEndpointLockManager() {} 96 ~WebSocketEndpointLockManager()97WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { 98 DCHECK(lock_info_map_.empty()); 99 DCHECK(socket_lock_info_map_.empty()); 100 } 101 UnlockEndpointByIterator(LockInfoMap::iterator lock_info_it)102void WebSocketEndpointLockManager::UnlockEndpointByIterator( 103 LockInfoMap::iterator lock_info_it) { 104 if (lock_info_it->second.socket) 105 EraseSocket(lock_info_it); 106 LockInfo::WaiterQueue* queue = lock_info_it->second.queue.get(); 107 DCHECK(queue); 108 if (queue->empty()) { 109 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString(); 110 lock_info_map_.erase(lock_info_it); 111 return; 112 } 113 114 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString() 115 << " and activating next waiter"; 116 Waiter* next_job = queue->head()->value(); 117 next_job->RemoveFromList(); 118 // This must be last to minimise the excitement caused by re-entrancy. 119 next_job->GotEndpointLock(); 120 } 121 EraseSocket(LockInfoMap::iterator lock_info_it)122void WebSocketEndpointLockManager::EraseSocket( 123 LockInfoMap::iterator lock_info_it) { 124 DVLOG(3) << "Removing (StreamSocket*)" << lock_info_it->second.socket 125 << " for " << lock_info_it->first.ToString() << " (" 126 << socket_lock_info_map_.size() << " socket(s) left)"; 127 size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket); 128 DCHECK_EQ(1U, erased); 129 lock_info_it->second.socket = NULL; 130 } 131 132 } // namespace net 133