OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/port.h" | 5 #include "vm/port.h" |
6 | 6 |
7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
8 #include "vm/dart_api_impl.h" | 8 #include "vm/dart_api_impl.h" |
9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
10 #include "vm/message_queue.h" | 10 #include "vm/message.h" |
11 #include "vm/thread.h" | 11 #include "vm/thread.h" |
12 | 12 |
13 namespace dart { | 13 namespace dart { |
14 | 14 |
15 DECLARE_FLAG(bool, trace_isolates); | 15 DECLARE_FLAG(bool, trace_isolates); |
16 | 16 |
17 Mutex* PortMap::mutex_ = NULL; | 17 Mutex* PortMap::mutex_ = NULL; |
18 | |
19 PortMap::Entry* PortMap::map_ = NULL; | 18 PortMap::Entry* PortMap::map_ = NULL; |
20 Isolate* PortMap::deleted_entry_ = reinterpret_cast<Isolate*>(1); | 19 MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1); |
21 intptr_t PortMap::capacity_ = 0; | 20 intptr_t PortMap::capacity_ = 0; |
22 intptr_t PortMap::used_ = 0; | 21 intptr_t PortMap::used_ = 0; |
23 intptr_t PortMap::deleted_ = 0; | 22 intptr_t PortMap::deleted_ = 0; |
24 | |
25 Dart_Port PortMap::next_port_ = 7111; | 23 Dart_Port PortMap::next_port_ = 7111; |
26 | 24 |
27 | 25 |
28 intptr_t PortMap::FindPort(Dart_Port port) { | 26 intptr_t PortMap::FindPort(Dart_Port port) { |
29 intptr_t index = port % capacity_; | 27 intptr_t index = port % capacity_; |
30 intptr_t start_index = index; | 28 intptr_t start_index = index; |
31 Entry entry = map_[index]; | 29 Entry entry = map_[index]; |
32 while (entry.isolate != NULL) { | 30 while (entry.handler != NULL) { |
33 if (entry.port == port) { | 31 if (entry.port == port) { |
34 return index; | 32 return index; |
35 } | 33 } |
36 index = (index + 1) % capacity_; | 34 index = (index + 1) % capacity_; |
37 // Prevent endless loops. | 35 // Prevent endless loops. |
38 ASSERT(index != start_index); | 36 ASSERT(index != start_index); |
39 entry = map_[index]; | 37 entry = map_[index]; |
40 } | 38 } |
41 return -1; | 39 return -1; |
42 } | 40 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 ASSERT(result != 0); | 74 ASSERT(result != 0); |
77 return result; | 75 return result; |
78 } | 76 } |
79 | 77 |
80 | 78 |
81 void PortMap::SetLive(Dart_Port port) { | 79 void PortMap::SetLive(Dart_Port port) { |
82 MutexLocker ml(mutex_); | 80 MutexLocker ml(mutex_); |
83 intptr_t index = FindPort(port); | 81 intptr_t index = FindPort(port); |
84 ASSERT(index >= 0); | 82 ASSERT(index >= 0); |
85 map_[index].live = true; | 83 map_[index].live = true; |
86 map_[index].isolate->increment_live_ports(); | 84 map_[index].handler->increment_live_ports(); |
87 } | 85 } |
88 | 86 |
89 | 87 |
90 void PortMap::MaintainInvariants() { | 88 void PortMap::MaintainInvariants() { |
91 intptr_t empty = capacity_ - used_ - deleted_; | 89 intptr_t empty = capacity_ - used_ - deleted_; |
92 if (used_ > ((capacity_ / 4) * 3)) { | 90 if (used_ > ((capacity_ / 4) * 3)) { |
93 // Grow the port map. | 91 // Grow the port map. |
94 Rehash(capacity_ * 2); | 92 Rehash(capacity_ * 2); |
95 } else if (empty < deleted_) { | 93 } else if (empty < deleted_) { |
96 // Rehash without growing the table to flush the deleted slots out of the | 94 // Rehash without growing the table to flush the deleted slots out of the |
97 // map. | 95 // map. |
98 Rehash(capacity_); | 96 Rehash(capacity_); |
99 } | 97 } |
100 } | 98 } |
101 | 99 |
102 | 100 |
103 Dart_Port PortMap::CreatePort() { | 101 Dart_Port PortMap::CreatePort(MessageHandler* handler) { |
104 Isolate* isolate = Isolate::Current(); | 102 ASSERT(handler != NULL); |
105 MutexLocker ml(mutex_); | 103 MutexLocker ml(mutex_); |
| 104 #if defined(DEBUG) |
| 105 handler->CheckAccess(); |
| 106 #endif |
106 | 107 |
107 Entry entry; | 108 Entry entry; |
108 entry.port = AllocatePort(); | 109 entry.port = AllocatePort(); |
109 entry.isolate = isolate; | 110 entry.handler = handler; |
110 entry.live = false; | 111 entry.live = false; |
111 | 112 |
112 // Search for the first unused slot. Make use of the knowledge that here is | 113 // Search for the first unused slot. Make use of the knowledge that here is |
113 // currently no port with this id in the port map. | 114 // currently no port with this id in the port map. |
114 ASSERT(FindPort(entry.port) < 0); | 115 ASSERT(FindPort(entry.port) < 0); |
115 intptr_t index = entry.port % capacity_; | 116 intptr_t index = entry.port % capacity_; |
116 Entry cur = map_[index]; | 117 Entry cur = map_[index]; |
117 // Stop the search at the first found unused (free or deleted) slot. | 118 // Stop the search at the first found unused (free or deleted) slot. |
118 while (cur.port != 0) { | 119 while (cur.port != 0) { |
119 index = (index + 1) % capacity_; | 120 index = (index + 1) % capacity_; |
120 cur = map_[index]; | 121 cur = map_[index]; |
121 } | 122 } |
122 | 123 |
123 // Insert the newly created port at the index. | 124 // Insert the newly created port at the index. |
124 ASSERT(index >= 0); | 125 ASSERT(index >= 0); |
125 ASSERT(index < capacity_); | 126 ASSERT(index < capacity_); |
126 ASSERT(map_[index].port == 0); | 127 ASSERT(map_[index].port == 0); |
127 ASSERT((map_[index].isolate == NULL) || | 128 ASSERT((map_[index].handler == NULL) || |
128 (map_[index].isolate == deleted_entry_)); | 129 (map_[index].handler == deleted_entry_)); |
129 if (map_[index].isolate == deleted_entry_) { | 130 if (map_[index].handler == deleted_entry_) { |
130 // Consuming a deleted entry. | 131 // Consuming a deleted entry. |
131 deleted_--; | 132 deleted_--; |
132 } | 133 } |
133 map_[index] = entry; | 134 map_[index] = entry; |
134 isolate->increment_num_ports(); | |
135 | 135 |
136 // Increment number of used slots and grow if necessary. | 136 // Increment number of used slots and grow if necessary. |
137 used_++; | 137 used_++; |
138 MaintainInvariants(); | 138 MaintainInvariants(); |
139 | 139 |
140 return entry.port; | 140 return entry.port; |
141 } | 141 } |
142 | 142 |
143 | 143 |
144 void PortMap::ClosePort(Dart_Port port) { | 144 bool PortMap::ClosePort(Dart_Port port) { |
145 Isolate* isolate = Isolate::Current(); | 145 MessageHandler* handler = NULL; |
146 { | 146 { |
147 MutexLocker ml(mutex_); | 147 MutexLocker ml(mutex_); |
148 intptr_t index = FindPort(port); | 148 intptr_t index = FindPort(port); |
149 if (index < 0) { | 149 if (index < 0) { |
150 return; | 150 return false; |
151 } | 151 } |
152 ASSERT(index < capacity_); | 152 ASSERT(index < capacity_); |
153 ASSERT(map_[index].port != 0); | 153 ASSERT(map_[index].port != 0); |
154 ASSERT(map_[index].isolate == isolate); | 154 ASSERT(map_[index].handler != deleted_entry_); |
| 155 ASSERT(map_[index].handler != NULL); |
| 156 |
| 157 handler = map_[index].handler; |
| 158 #if defined(DEBUG) |
| 159 handler->CheckAccess(); |
| 160 #endif |
155 // Before releasing the lock mark the slot in the map as deleted. This makes | 161 // Before releasing the lock mark the slot in the map as deleted. This makes |
156 // it possible to release the port map lock before flushing all of its | 162 // it possible to release the port map lock before flushing all of its |
157 // pending messages below. | 163 // pending messages below. |
158 map_[index].port = 0; | 164 map_[index].port = 0; |
159 map_[index].isolate = deleted_entry_; | 165 map_[index].handler = deleted_entry_; |
160 isolate->decrement_num_ports(); | |
161 if (map_[index].live) { | 166 if (map_[index].live) { |
162 isolate->decrement_live_ports(); | 167 handler->decrement_live_ports(); |
163 } | 168 } |
164 | 169 |
165 used_--; | 170 used_--; |
166 deleted_++; | 171 deleted_++; |
167 MaintainInvariants(); | 172 MaintainInvariants(); |
168 } | 173 } |
169 isolate->ClosePort(port); | 174 handler->ClosePort(port); |
| 175 if (!handler->HasLivePorts() && handler->OwnedByPortMap()) { |
| 176 delete handler; |
| 177 } |
| 178 return true; |
170 } | 179 } |
171 | 180 |
172 | 181 |
173 void PortMap::ClosePorts() { | 182 void PortMap::ClosePorts(MessageHandler* handler) { |
174 Isolate* isolate = Isolate::Current(); | |
175 { | 183 { |
176 MutexLocker ml(mutex_); | 184 MutexLocker ml(mutex_); |
177 for (intptr_t i = 0; i < capacity_; i++) { | 185 for (intptr_t i = 0; i < capacity_; i++) { |
178 if (map_[i].isolate == isolate) { | 186 if (map_[i].handler == handler) { |
179 // Mark the slot as deleted. | 187 // Mark the slot as deleted. |
180 map_[i].port = 0; | 188 map_[i].port = 0; |
181 map_[i].isolate = deleted_entry_; | 189 map_[i].handler = deleted_entry_; |
182 isolate->decrement_num_ports(); | 190 if (map_[i].live) { |
183 | 191 handler->decrement_live_ports(); |
| 192 } |
184 used_--; | 193 used_--; |
185 deleted_++; | 194 deleted_++; |
186 } | 195 } |
187 } | 196 } |
188 MaintainInvariants(); | 197 MaintainInvariants(); |
189 } | 198 } |
190 isolate->CloseAllPorts(); | 199 handler->CloseAllPorts(); |
191 } | 200 } |
192 | 201 |
193 | 202 |
194 bool PortMap::PostMessage(Message* message) { | 203 bool PortMap::PostMessage(Message* message) { |
195 // TODO(turnidge): Add a scoped locker for mutexes which is not a | 204 MutexLocker ml(mutex_); |
196 // stack resource. This would probably be useful in the platform | |
197 // headers. | |
198 mutex_->Lock(); | |
199 intptr_t index = FindPort(message->dest_port()); | 205 intptr_t index = FindPort(message->dest_port()); |
200 if (index < 0) { | 206 if (index < 0) { |
201 free(message); | 207 free(message); |
202 mutex_->Unlock(); | |
203 return false; | 208 return false; |
204 } | 209 } |
205 ASSERT(index >= 0); | 210 ASSERT(index >= 0); |
206 ASSERT(index < capacity_); | 211 ASSERT(index < capacity_); |
207 Isolate* isolate = map_[index].isolate; | 212 MessageHandler* handler = map_[index].handler; |
208 ASSERT(map_[index].port != 0); | 213 ASSERT(map_[index].port != 0); |
209 ASSERT((isolate != NULL) && (isolate != deleted_entry_)); | 214 ASSERT((handler != NULL) && (handler != deleted_entry_)); |
210 isolate->PostMessage(message); | 215 handler->PostMessage(message); |
211 mutex_->Unlock(); | |
212 return true; | 216 return true; |
213 } | 217 } |
214 | 218 |
215 | 219 |
216 void PortMap::InitOnce() { | 220 void PortMap::InitOnce() { |
217 mutex_ = new Mutex(); | 221 mutex_ = new Mutex(); |
218 | 222 |
219 static const intptr_t kInitialCapacity = 8; | 223 static const intptr_t kInitialCapacity = 8; |
220 // TODO(iposva): Verify whether we want to keep exponentially growing. | 224 // TODO(iposva): Verify whether we want to keep exponentially growing. |
221 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); | 225 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); |
222 map_ = new Entry[kInitialCapacity]; | 226 map_ = new Entry[kInitialCapacity]; |
223 memset(map_, 0, kInitialCapacity * sizeof(Entry)); | 227 memset(map_, 0, kInitialCapacity * sizeof(Entry)); |
224 capacity_ = kInitialCapacity; | 228 capacity_ = kInitialCapacity; |
225 used_ = 0; | 229 used_ = 0; |
226 deleted_ = 0; | 230 deleted_ = 0; |
227 } | 231 } |
228 | 232 |
229 | |
230 } // namespace dart | 233 } // namespace dart |
OLD | NEW |