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.
5 #include "net/socket/websocket_endpoint_lock_manager.h"
9 #include "base/logging.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/net_log.h"
15 WebSocketEndpointLockManager::Waiter::~Waiter() {
22 WebSocketEndpointLockManager
* WebSocketEndpointLockManager::GetInstance() {
23 return Singleton
<WebSocketEndpointLockManager
>::get();
26 int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint
& endpoint
,
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
;
33 DVLOG(3) << "Locking endpoint " << endpoint
.ToString();
34 lock_info_in_map
.queue
.reset(new LockInfo::WaiterQueue
);
37 DVLOG(3) << "Waiting for endpoint " << endpoint
.ToString();
38 lock_info_in_map
.queue
->Append(waiter
);
39 return ERR_IO_PENDING
;
42 void 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());
47 socket_lock_info_map_
.insert(SocketLockInfoMap::value_type(
48 socket
, lock_info_it
)).second
;
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)";
57 void WebSocketEndpointLockManager::UnlockSocket(StreamSocket
* socket
) {
58 SocketLockInfoMap::iterator socket_it
= socket_lock_info_map_
.find(socket
);
59 if (socket_it
== socket_lock_info_map_
.end())
62 LockInfoMap::iterator lock_info_it
= socket_it
->second
;
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
);
73 void 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())
78 UnlockEndpointByIterator(lock_info_it
);
81 bool WebSocketEndpointLockManager::IsEmpty() const {
82 return lock_info_map_
.empty() && socket_lock_info_map_
.empty();
85 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL
) {}
86 WebSocketEndpointLockManager::LockInfo::~LockInfo() {
90 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo
& rhs
)
91 : socket(rhs
.socket
) {
95 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {}
97 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
98 DCHECK(lock_info_map_
.empty());
99 DCHECK(socket_lock_info_map_
.empty());
102 void 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();
108 if (queue
->empty()) {
109 DVLOG(3) << "Unlocking endpoint " << lock_info_it
->first
.ToString();
110 lock_info_map_
.erase(lock_info_it
);
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();
122 void 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
;