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