Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / socket / websocket_endpoint_lock_manager.cc
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
15 WebSocketEndpointLockManager::Waiter::~Waiter() {
16   if (next()) {
17     DCHECK(previous());
18     RemoveFromList();
19   }
20 }
21
22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() {
23   return Singleton<WebSocketEndpointLockManager>::get();
24 }
25
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;
36   }
37   DVLOG(3) << "Waiting for endpoint " << endpoint.ToString();
38   lock_info_in_map.queue->Append(waiter);
39   return ERR_IO_PENDING;
40 }
41
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)";
55 }
56
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;
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
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;
77
78   UnlockEndpointByIterator(lock_info_it);
79 }
80
81 bool WebSocketEndpointLockManager::IsEmpty() const {
82   return lock_info_map_.empty() && socket_lock_info_map_.empty();
83 }
84
85 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {}
86 WebSocketEndpointLockManager::LockInfo::~LockInfo() {
87   DCHECK(!socket);
88 }
89
90 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs)
91     : socket(rhs.socket) {
92   DCHECK(!rhs.queue);
93 }
94
95 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {}
96
97 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
98   DCHECK(lock_info_map_.empty());
99   DCHECK(socket_lock_info_map_.empty());
100 }
101
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;
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
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;
130 }
131
132 }  // namespace net