Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: runtime/vm/port.cc

Issue 8297004: Allow embedders to provide custom message delivery for an isolate. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/port.h ('k') | runtime/vm/port_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 "vm/isolate.h"
8 #include "vm/thread.h"
9 #include "vm/utils.h"
10
7 namespace dart { 11 namespace dart {
8 12
9 MessageQueue::~MessageQueue() {
10 // Ensure that all pending messages have been released.
11 ASSERT(head_ == NULL);
12 }
13
14
15 void MessageQueue::Enqueue(PortMessage* msg) {
16 // Make sure messages are not reused.
17 ASSERT(msg->next_ == NULL);
18 if (head_ == NULL) {
19 // Only element in the queue.
20 head_ = msg;
21 tail_ = msg;
22 } else {
23 ASSERT(tail_ != NULL);
24 // Append at the tail.
25 tail_->next_ = msg;
26 tail_ = msg;
27 }
28 }
29
30
31 PortMessage* MessageQueue::Dequeue() {
32 PortMessage* result = head_;
33 if (result != NULL) {
34 head_ = result->next_;
35 // The following update to tail_ is not strictly needed.
36 if (head_ == NULL) {
37 tail_ = NULL;
38 }
39 #if DEBUG
40 result->next_ = result; // Make sure to trigger ASSERT in Enqueue.
41 #endif // DEBUG
42 }
43 return result;
44 }
45
46
47 void MessageQueue::Flush(intptr_t port_id) {
48 PortMessage* cur = head_;
49 PortMessage* prev = NULL;
50 while (cur != NULL) {
51 PortMessage* next = cur->next_;
52 // If the message matches, then remove it from the queue and delete it.
53 if (cur->dest_id() == port_id) {
54 if (prev != NULL) {
55 prev->next_ = next;
56 } else {
57 head_ = next;
58 }
59 delete cur;
60 } else {
61 // Move prev forward.
62 prev = cur;
63 }
64 // Advance to the next message in the queue.
65 cur = next;
66 }
67 tail_ = prev;
68 }
69
70
71 void MessageQueue::FlushAll() {
72 PortMessage* cur = head_;
73 head_ = NULL;
74 tail_ = NULL;
75 while (cur != NULL) {
76 PortMessage* next = cur->next_;
77 delete next;
78 cur = next;
79 }
80 }
81
82 13
83 Mutex* PortMap::mutex_ = NULL; 14 Mutex* PortMap::mutex_ = NULL;
84 15
85 PortMap::Entry* PortMap::map_ = NULL; 16 PortMap::Entry* PortMap::map_ = NULL;
86 Isolate* PortMap::deleted_entry_ = reinterpret_cast<Isolate*>(1); 17 Isolate* PortMap::deleted_entry_ = reinterpret_cast<Isolate*>(1);
87 intptr_t PortMap::capacity_ = 0; 18 intptr_t PortMap::capacity_ = 0;
88 intptr_t PortMap::used_ = 0; 19 intptr_t PortMap::used_ = 0;
89 intptr_t PortMap::deleted_ = 0; 20 intptr_t PortMap::deleted_ = 0;
90 21
91 intptr_t PortMap::next_id_ = 7111; 22 Dart_Port PortMap::next_port_ = 7111;
92 23
93 24
94 intptr_t PortMap::FindId(intptr_t id) { 25 intptr_t PortMap::FindPort(Dart_Port port) {
95 intptr_t index = id % capacity_; 26 intptr_t index = port % capacity_;
96 intptr_t start_index = index; 27 intptr_t start_index = index;
97 Entry entry = map_[index]; 28 Entry entry = map_[index];
98 while (entry.isolate != NULL) { 29 while (entry.isolate != NULL) {
99 if (entry.id == id) { 30 if (entry.port == port) {
100 return index; 31 return index;
101 } 32 }
102 index = (index + 1) % capacity_; 33 index = (index + 1) % capacity_;
103 // Prevent endless loops. 34 // Prevent endless loops.
104 ASSERT(index != start_index); 35 ASSERT(index != start_index);
105 entry = map_[index]; 36 entry = map_[index];
106 } 37 }
107 return -1; 38 return -1;
108 } 39 }
109 40
110 41
111 void PortMap::Rehash(intptr_t new_capacity) { 42 void PortMap::Rehash(intptr_t new_capacity) {
112 Entry* new_ports = new Entry[new_capacity]; 43 Entry* new_ports = new Entry[new_capacity];
113 memset(new_ports, 0, new_capacity * sizeof(Entry)); 44 memset(new_ports, 0, new_capacity * sizeof(Entry));
114 45
115 for (intptr_t i = 0; i < capacity_; i++) { 46 for (intptr_t i = 0; i < capacity_; i++) {
116 Entry entry = map_[i]; 47 Entry entry = map_[i];
117 // Skip free and deleted entries. 48 // Skip free and deleted entries.
118 if (entry.id != 0) { 49 if (entry.port != 0) {
119 intptr_t new_index = entry.id % new_capacity; 50 intptr_t new_index = entry.port % new_capacity;
120 while (new_ports[new_index].id != 0) { 51 while (new_ports[new_index].port != 0) {
121 new_index = (new_index + 1) % new_capacity; 52 new_index = (new_index + 1) % new_capacity;
122 } 53 }
123 new_ports[new_index] = entry; 54 new_ports[new_index] = entry;
124 } 55 }
125 } 56 }
126 delete map_; 57 delete map_;
127 map_ = new_ports; 58 map_ = new_ports;
128 capacity_ = new_capacity; 59 capacity_ = new_capacity;
129 deleted_ = 0; 60 deleted_ = 0;
130 } 61 }
131 62
132 63
133 intptr_t PortMap::AllocateId() { 64 Dart_Port PortMap::AllocatePort() {
134 intptr_t result = next_id_; 65 Dart_Port result = next_port_;
135 66
136 do { 67 do {
137 // TODO(iposva): Use an approved hashing function to have less predictable 68 // TODO(iposva): Use an approved hashing function to have less predictable
138 // port ids, or make them not accessible from Dart code or both. 69 // port ids, or make them not accessible from Dart code or both.
139 next_id_++; 70 next_port_++;
140 } while (FindId(next_id_) >= 0); 71 } while (FindPort(next_port_) >= 0);
141 72
142 ASSERT(result != 0); 73 ASSERT(result != 0);
143 return result; 74 return result;
144 } 75 }
145 76
146 77
147 void PortMap::MaintainInvariants() { 78 void PortMap::MaintainInvariants() {
148 intptr_t empty = capacity_ - used_ - deleted_; 79 intptr_t empty = capacity_ - used_ - deleted_;
149 if (used_ > ((capacity_ / 4) * 3)) { 80 if (used_ > ((capacity_ / 4) * 3)) {
150 // Grow the port map. 81 // Grow the port map.
151 Rehash(capacity_ * 2); 82 Rehash(capacity_ * 2);
152 } else if (empty < deleted_) { 83 } else if (empty < deleted_) {
153 // Rehash without growing the table to flush the deleted slots out of the 84 // Rehash without growing the table to flush the deleted slots out of the
154 // map. 85 // map.
155 Rehash(capacity_); 86 Rehash(capacity_);
156 } 87 }
157 } 88 }
158 89
159 90
160 intptr_t PortMap::CreatePort() { 91 Dart_Port PortMap::CreatePort() {
161 Isolate* isolate = Isolate::Current(); 92 Isolate* isolate = Isolate::Current();
162 93
163 MutexLocker ml(mutex_); 94 MutexLocker ml(mutex_);
164 95
165 Entry entry; 96 Entry entry;
166 entry.id = AllocateId(); 97 entry.port = AllocatePort();
167 entry.isolate = isolate; 98 entry.isolate = isolate;
168 99
169 // Search for the first unused slot. Make use of the knowledge that here is 100 // Search for the first unused slot. Make use of the knowledge that here is
170 // currently no port with this id in the port map. 101 // currently no port with this id in the port map.
171 ASSERT(FindId(entry.id) < 0); 102 ASSERT(FindPort(entry.port) < 0);
172 intptr_t index = entry.id % capacity_; 103 intptr_t index = entry.port % capacity_;
173 Entry cur = map_[index]; 104 Entry cur = map_[index];
174 // Stop the search at the first found unused (free or deleted) slot. 105 // Stop the search at the first found unused (free or deleted) slot.
175 while (cur.id != 0) { 106 while (cur.port != 0) {
176 index = (index + 1) % capacity_; 107 index = (index + 1) % capacity_;
177 cur = map_[index]; 108 cur = map_[index];
178 } 109 }
179 110
180 // Insert the newly created port at the index. 111 // Insert the newly created port at the index.
181 ASSERT(index >= 0); 112 ASSERT(index >= 0);
182 ASSERT(index < capacity_); 113 ASSERT(index < capacity_);
183 ASSERT(map_[index].id == 0); 114 ASSERT(map_[index].port == 0);
184 ASSERT((map_[index].isolate == NULL) || 115 ASSERT((map_[index].isolate == NULL) ||
185 (map_[index].isolate == deleted_entry_)); 116 (map_[index].isolate == deleted_entry_));
186 if (map_[index].isolate == deleted_entry_) { 117 if (map_[index].isolate == deleted_entry_) {
187 // Consuming a deleted entry. 118 // Consuming a deleted entry.
188 deleted_--; 119 deleted_--;
189 } 120 }
190 map_[index] = entry; 121 map_[index] = entry;
191 isolate->increment_active_ports(); 122 isolate->increment_active_ports();
192 123
193 // Increment number of used slots and grow if necessary. 124 // Increment number of used slots and grow if necessary.
194 used_++; 125 used_++;
195 MaintainInvariants(); 126 MaintainInvariants();
196 127
197 return entry.id; 128 return entry.port;
198 } 129 }
199 130
200 131
201 void PortMap::ClosePort(intptr_t id) { 132 void PortMap::ClosePort(Dart_Port port) {
202 Isolate* isolate = Isolate::Current(); 133 Isolate* isolate = Isolate::Current();
203 { 134 {
204 MutexLocker ml(mutex_); 135 MutexLocker ml(mutex_);
205 intptr_t index = FindId(id); 136 intptr_t index = FindPort(port);
206 if (index < 0) { 137 if (index < 0) {
207 return; 138 return;
208 } 139 }
209 ASSERT(index < capacity_); 140 ASSERT(index < capacity_);
210 ASSERT(map_[index].id != 0); 141 ASSERT(map_[index].port != 0);
211 ASSERT(map_[index].isolate == isolate); 142 ASSERT(map_[index].isolate == isolate);
212 // Before releasing the lock mark the slot in the map as deleted. This makes 143 // Before releasing the lock mark the slot in the map as deleted. This makes
213 // it possible to release the port map lock before flushing all of its 144 // it possible to release the port map lock before flushing all of its
214 // pending messages below. 145 // pending messages below.
215 map_[index].id = 0; 146 map_[index].port = 0;
216 map_[index].isolate = deleted_entry_; 147 map_[index].isolate = deleted_entry_;
217 isolate->decrement_active_ports(); 148 isolate->decrement_active_ports();
218 149
219 used_--; 150 used_--;
220 deleted_++; 151 deleted_++;
221 MaintainInvariants(); 152 MaintainInvariants();
222 } 153 }
223 { 154
224 // Remove the pending messages for this port. 155 // Notify the embedder that this port is closed.
225 MonitorLocker ml(isolate->monitor()); 156 Dart_ClosePortCallback callback = isolate->close_port_callback();
226 isolate->message_queue()->Flush(id); 157 ASSERT(callback);
227 } 158 ASSERT(port != kCloseAllPorts);
159 (*callback)(isolate, port);
228 } 160 }
229 161
230 162
231 void PortMap::ClosePorts() { 163 void PortMap::ClosePorts() {
232 Isolate* isolate = Isolate::Current(); 164 Isolate* isolate = Isolate::Current();
233 { 165 {
234 MutexLocker ml(mutex_); 166 MutexLocker ml(mutex_);
235 for (intptr_t i = 0; i < capacity_; i++) { 167 for (intptr_t i = 0; i < capacity_; i++) {
236 if (map_[i].isolate == isolate) { 168 if (map_[i].isolate == isolate) {
237 // Mark the slot as deleted. 169 // Mark the slot as deleted.
238 map_[i].id = 0; 170 map_[i].port = 0;
239 map_[i].isolate = deleted_entry_; 171 map_[i].isolate = deleted_entry_;
240 isolate->decrement_active_ports(); 172 isolate->decrement_active_ports();
241 173
242 used_--; 174 used_--;
243 deleted_++; 175 deleted_++;
244 } 176 }
245 } 177 }
246 MaintainInvariants(); 178 MaintainInvariants();
247 } 179 }
248 isolate->message_queue()->FlushAll(); 180
181 // Notify the embedder that all ports are closed.
182 Dart_ClosePortCallback callback = isolate->close_port_callback();
183 ASSERT(callback);
184 (*callback)(isolate, kCloseAllPorts);
249 } 185 }
250 186
251 187
252 bool PortMap::IsActivePort(intptr_t id) { 188 bool PortMap::IsActivePort(Dart_Port port) {
253 MutexLocker ml(mutex_); 189 MutexLocker ml(mutex_);
254 return (FindId(id) >= 0); 190 return (FindPort(port) >= 0);
255 } 191 }
256 192
257 193
258 bool PortMap::PostMessage(PortMessage* msg) { 194 bool PortMap::PostMessage(Dart_Port dest_port,
259 intptr_t id = msg->dest_id(); 195 Dart_Port reply_port,
196 Dart_Message message) {
260 mutex_->Lock(); 197 mutex_->Lock();
261 intptr_t index = FindId(id); 198 intptr_t index = FindPort(dest_port);
262 if (index < 0) { 199 if (index < 0) {
200 free(message);
263 mutex_->Unlock(); 201 mutex_->Unlock();
264 return false; 202 return false;
265 } 203 }
266 ASSERT(index >= 0); 204 ASSERT(index >= 0);
267 ASSERT(index < capacity_); 205 ASSERT(index < capacity_);
268 Isolate* isolate = map_[index].isolate; 206 Isolate* isolate = map_[index].isolate;
269 ASSERT(map_[index].id != 0); 207 ASSERT(map_[index].port != 0);
270 ASSERT((isolate != NULL) && (isolate != deleted_entry_)); 208 ASSERT((isolate != NULL) && (isolate != deleted_entry_));
271 Monitor* monitor = isolate->monitor(); 209
272 monitor->Enter(); 210 // Delegate message delivery to the embedder.
273 isolate->message_queue()->Enqueue(msg); 211 Dart_PostMessageCallback callback = isolate->post_message_callback();
274 monitor->Notify(); 212 ASSERT(callback);
275 monitor->Exit(); 213 bool result = (*callback)(isolate, dest_port, reply_port, message);
214
276 mutex_->Unlock(); 215 mutex_->Unlock();
277 return true; 216 return result;
278 } 217 }
279 218
280 219
281 PortMessage* PortMap::ReceiveMessage(int64_t millis) {
282 // Since only the isolate owning the port can close the port and remove it
283 // from the port map and flush its messages, we can safely assume that the
284 // all messages in the message queue are for active ports.
285 Isolate* isolate = Isolate::Current();
286 {
287 MonitorLocker ml(isolate->monitor());
288 PortMessage* result = isolate->message_queue()->Dequeue();
289 if (result == NULL) {
290 ml.Wait(millis);
291 result = isolate->message_queue()->Dequeue();
292 // We will return a NULL message for spurious wakeups or timeouts.
293 }
294 return result;
295 }
296 }
297
298
299 void PortMap::InitOnce() { 220 void PortMap::InitOnce() {
300 mutex_ = new Mutex(); 221 mutex_ = new Mutex();
301 222
302 static const intptr_t kInitialCapacity = 8; 223 static const intptr_t kInitialCapacity = 8;
303 // TODO(iposva): Verify whether we want to keep exponentially growing. 224 // TODO(iposva): Verify whether we want to keep exponentially growing.
304 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity)); 225 ASSERT(Utils::IsPowerOfTwo(kInitialCapacity));
305 map_ = new Entry[kInitialCapacity]; 226 map_ = new Entry[kInitialCapacity];
306 memset(map_, 0, kInitialCapacity * sizeof(Entry)); 227 memset(map_, 0, kInitialCapacity * sizeof(Entry));
307 capacity_ = kInitialCapacity; 228 capacity_ = kInitialCapacity;
308 used_ = 0; 229 used_ = 0;
309 deleted_ = 0; 230 deleted_ = 0;
310 } 231 }
311 232
312 233
313 } // namespace dart 234 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/port.h ('k') | runtime/vm/port_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698