Chromecast: adds class to help record complex histograms.
[chromium-blink-merge.git] / net / socket / websocket_endpoint_lock_manager.cc
blobe578bb2435b314cb18fb223e749b7093ec4c2c60
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"
7 #include <utility>
9 #include "base/logging.h"
10 #include "net/base/net_errors.h"
11 #include "net/base/net_log.h"
13 namespace net {
15 WebSocketEndpointLockManager::Waiter::~Waiter() {
16 if (next()) {
17 DCHECK(previous());
18 RemoveFromList();
22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() {
23 return Singleton<WebSocketEndpointLockManager>::get();
26 int 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;
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());
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)";
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())
60 return;
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())
76 return;
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() {
87 DCHECK(!socket);
90 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs)
91 : socket(rhs.socket) {
92 DCHECK(!rhs.queue);
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();
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;
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;
132 } // namespace net