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