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 #ifndef BIN_EVENTHANDLER_H_ | 5 #ifndef BIN_EVENTHANDLER_H_ |
6 #define BIN_EVENTHANDLER_H_ | 6 #define BIN_EVENTHANDLER_H_ |
7 | 7 |
8 #include "bin/builtin.h" | 8 #include "bin/builtin.h" |
9 #include "bin/dartutils.h" | |
10 #include "bin/isolate_data.h" | 9 #include "bin/isolate_data.h" |
11 | 10 |
12 #include "platform/hashmap.h" | |
13 | |
14 namespace dart { | 11 namespace dart { |
15 namespace bin { | 12 namespace bin { |
16 | 13 |
17 // Flags used to provide information and actions to the eventhandler | 14 // Flags used to provide information and actions to the eventhandler |
18 // when sending a message about a file descriptor. These flags should | 15 // when sending a message about a file descriptor. These flags should |
19 // be kept in sync with the constants in socket_impl.dart. For more | 16 // be kept in sync with the constants in socket_impl.dart. For more |
20 // information see the comments in socket_impl.dart | 17 // information see the comments in socket_impl.dart |
21 enum MessageFlags { | 18 enum MessageFlags { |
22 kInEvent = 0, | 19 kInEvent = 0, |
23 kOutEvent = 1, | 20 kOutEvent = 1, |
24 kErrorEvent = 2, | 21 kErrorEvent = 2, |
25 kCloseEvent = 3, | 22 kCloseEvent = 3, |
26 kDestroyedEvent = 4, | 23 kDestroyedEvent = 4, |
27 kCloseCommand = 8, | 24 kCloseCommand = 8, |
28 kShutdownReadCommand = 9, | 25 kShutdownReadCommand = 9, |
29 kShutdownWriteCommand = 10, | 26 kShutdownWriteCommand = 10, |
30 kReturnTokenCommand = 11, | 27 kReturnTokenCommand = 11, |
31 kListeningSocket = 16, | 28 kListeningSocket = 16, |
32 kPipe = 17, | 29 kPipe = 17, |
33 }; | 30 }; |
34 | 31 |
35 #define EVENT_MASK ((1 << kInEvent) | \ | |
36 (1 << kOutEvent) | \ | |
37 (1 << kErrorEvent) | \ | |
38 (1 << kCloseEvent) | \ | |
39 (1 << kDestroyedEvent)) | |
40 #define COMMAND_MASK ((1 << kCloseCommand) | \ | 32 #define COMMAND_MASK ((1 << kCloseCommand) | \ |
41 (1 << kShutdownReadCommand) | \ | 33 (1 << kShutdownReadCommand) | \ |
42 (1 << kShutdownWriteCommand) | \ | 34 (1 << kShutdownWriteCommand) | \ |
43 (1 << kReturnTokenCommand)) | 35 (1 << kReturnTokenCommand)) |
44 #define IS_COMMAND(data, command_bit) \ | 36 #define IS_COMMAND(data, command_bit) \ |
45 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT | 37 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT |
46 #define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0) // NOLINT | 38 #define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0) // NOLINT |
47 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) | 39 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) |
48 | 40 |
49 class TimeoutQueue { | 41 class TimeoutQueue { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 UpdateTimeout(CurrentPort(), -1); | 87 UpdateTimeout(CurrentPort(), -1); |
96 } | 88 } |
97 | 89 |
98 void UpdateTimeout(Dart_Port port, int64_t timeout); | 90 void UpdateTimeout(Dart_Port port, int64_t timeout); |
99 | 91 |
100 private: | 92 private: |
101 Timeout* next_timeout_; | 93 Timeout* next_timeout_; |
102 Timeout* timeouts_; | 94 Timeout* timeouts_; |
103 }; | 95 }; |
104 | 96 |
105 | |
106 template<typename T> | |
107 class CircularLinkedList { | |
108 public: | |
109 CircularLinkedList() : head_(NULL) {} | |
110 | |
111 // Returns true if the list was empty. | |
112 bool Add(T t) { | |
113 Entry* e = new Entry(t); | |
114 if (head_ == NULL) { | |
115 // Empty list, make e head, and point to itself. | |
116 e->next_ = e; | |
117 e->prev_ = e; | |
118 head_ = e; | |
119 return true; | |
120 } else { | |
121 // Insert e as the last element in the list. | |
122 e->prev_ = head_->prev_; | |
123 e->next_ = head_; | |
124 e->prev_->next_ = e; | |
125 head_->prev_ = e; | |
126 return false; | |
127 } | |
128 } | |
129 | |
130 void RemoveHead() { | |
131 Entry* e = head_; | |
132 if (e->next_ == e) { | |
133 head_ = NULL; | |
134 } else { | |
135 e->prev_->next_ = e->next_; | |
136 e->next_->prev_ = e->prev_; | |
137 head_ = e->next_; | |
138 } | |
139 delete e; | |
140 } | |
141 | |
142 void Remove(T item) { | |
143 if (head_ == NULL) { | |
144 return; | |
145 } else if (head_ == head_->next_) { | |
146 if (head_->t == item) { | |
147 head_ = NULL; | |
148 return; | |
149 } | |
150 } else { | |
151 Entry *current = head_; | |
152 do { | |
153 if (current->t == item) { | |
154 Entry *next = current->next_; | |
155 Entry *prev = current->prev_; | |
156 prev->next_ = next; | |
157 next->prev_ = prev; | |
158 delete current; | |
159 return; | |
160 } | |
161 } while (current != head_); | |
162 } | |
163 } | |
164 | |
165 T head() const { return head_->t; } | |
166 | |
167 bool HasHead() const { | |
168 return head_ != NULL; | |
169 } | |
170 | |
171 void Rotate() { | |
172 head_ = head_->next_; | |
173 } | |
174 | |
175 private: | |
176 struct Entry { | |
177 explicit Entry(const T& t) : t(t) {} | |
178 const T t; | |
179 Entry* next_; | |
180 Entry* prev_; | |
181 }; | |
182 | |
183 Entry* head_; | |
184 }; | |
185 | |
186 | |
187 class DescriptorInfoBase { | |
188 public: | |
189 explicit DescriptorInfoBase(intptr_t fd) : fd_(fd) { | |
190 ASSERT(fd_ != -1); | |
191 } | |
192 | |
193 virtual ~DescriptorInfoBase() {} | |
194 | |
195 intptr_t fd() { return fd_; } | |
196 | |
197 | |
198 // Type of socket. | |
199 | |
200 virtual bool IsListeningSocket() const = 0; | |
201 | |
202 | |
203 // Ports. | |
204 | |
205 virtual bool SetPortAndMask(Dart_Port port, intptr_t mask) = 0; | |
206 | |
207 virtual bool RemovePort(Dart_Port port) = 0; | |
208 | |
209 // Returns the next port which should be used for sending events to. | |
210 virtual Dart_Port NextPort() = 0; | |
211 | |
212 virtual bool HasNextPort() = 0; | |
213 | |
214 // Will post `data` to all known Dart_Ports. | |
215 virtual void SendToAll(uintptr_t data) = 0; | |
216 | |
217 | |
218 // Tokens. | |
219 | |
220 // Returns true if the last token was taken. | |
221 virtual bool TakeToken() = 0; | |
222 | |
223 // Returns true if the tokens was 0 before adding. | |
224 virtual bool ReturnTokens(Dart_Port port, int count) = 0; | |
225 | |
226 // Returns true if for any registired Dart_port tokens are available. | |
227 virtual bool HasTokens() const = 0; | |
228 | |
229 | |
230 // Other. | |
231 | |
232 virtual intptr_t Mask() = 0; | |
233 | |
234 virtual void Close() = 0; | |
235 | |
236 protected: | |
237 intptr_t fd_; | |
238 }; | |
239 | |
240 | |
241 // Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on | |
242 // windows) which is connected to a single Dart_Port. | |
243 // | |
244 // Subclasses of this class can be e.g. connected tcp sockets | |
245 template<typename SI> | |
246 class DescriptorInfoSingleMixin : public SI { | |
247 public: | |
248 explicit DescriptorInfoSingleMixin(intptr_t fd) | |
249 : SI(fd), port_(0), tokens_(16), mask_(0) {} | |
250 | |
251 virtual ~DescriptorInfoSingleMixin() { } | |
252 | |
253 virtual bool IsListeningSocket() const { return false; } | |
254 | |
255 virtual bool SetPortAndMask(Dart_Port port, intptr_t mask) { | |
256 ASSERT(port_ == 0 || port == port_); | |
257 port_ = port; | |
258 mask_ = mask; | |
259 return true; | |
260 } | |
261 | |
262 virtual bool RemovePort(Dart_Port port) { | |
263 // TODO(kustermann): Find out where we call RemovePort() with the invalid | |
264 // port. Afterwards remove the part in the ASSERT here. | |
265 ASSERT(port_ == 0 || port_ == port); | |
266 port_ = 0; | |
267 return true; | |
268 } | |
269 | |
270 virtual Dart_Port NextPort() { | |
271 ASSERT(port_ != 0); | |
272 return port_; | |
273 } | |
274 | |
275 virtual bool HasNextPort() { | |
276 return port_ != 0; | |
277 } | |
278 | |
279 virtual void SendToAll(uintptr_t data) { | |
280 if (port_ != 0) { | |
281 DartUtils::PostInt32(port_, data); | |
282 } | |
283 } | |
284 | |
285 virtual bool TakeToken() { | |
286 ASSERT(tokens_ > 0); | |
287 tokens_--; | |
288 return tokens_ == 0; | |
289 } | |
290 | |
291 virtual bool ReturnTokens(Dart_Port port, int count) { | |
292 ASSERT(port_ == port); | |
293 ASSERT(tokens_ >= 0); | |
294 bool was_empty = tokens_ == 0; | |
295 tokens_ += count; | |
296 return was_empty; | |
297 } | |
298 | |
299 virtual bool HasTokens() const { return tokens_ > 0; } | |
300 | |
301 virtual intptr_t Mask() { | |
302 return mask_; | |
303 } | |
304 | |
305 virtual void Close() { | |
306 SI::Close(); | |
307 } | |
308 | |
309 private: | |
310 Dart_Port port_; | |
311 int tokens_; | |
312 intptr_t mask_; | |
313 }; | |
314 | |
315 | |
316 // Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on | |
317 // windows) which is connected to multiple Dart_Port's. | |
318 // | |
319 // Subclasses of this class can be e.g. a listening socket which multiple | |
320 // isolates are listening on. | |
321 template<typename SI> | |
322 class DescriptorInfoMultipleMixin : public SI { | |
323 private: | |
324 static const int kTokenCount = 4; | |
325 | |
326 static bool SamePortValue(void* key1, void* key2) { | |
327 return reinterpret_cast<Dart_Port>(key1) == | |
328 reinterpret_cast<Dart_Port>(key2); | |
329 } | |
330 | |
331 static uint32_t GetHashmapHashFromPort(Dart_Port port) { | |
332 return static_cast<uint32_t>(port & 0xFFFFFFFF); | |
333 } | |
334 | |
335 static void* GetHashmapKeyFromPort(Dart_Port port) { | |
336 return reinterpret_cast<void*>(port); | |
337 } | |
338 | |
339 static bool IsReadingMask(intptr_t mask) { | |
340 if (mask == (1 << kInEvent)) { | |
341 return true; | |
342 } else { | |
343 ASSERT(mask == 0); | |
344 return false; | |
345 } | |
346 } | |
347 | |
348 struct PortEntry { | |
349 Dart_Port dart_port; | |
350 intptr_t is_reading; | |
351 intptr_t token_count; | |
352 | |
353 bool IsReady() { return token_count > 0 && is_reading; } | |
354 }; | |
355 | |
356 public: | |
357 explicit DescriptorInfoMultipleMixin(intptr_t fd) | |
358 : SI(fd), tokens_map_(&SamePortValue, 4) {} | |
359 | |
360 virtual ~DescriptorInfoMultipleMixin() {} | |
361 | |
362 virtual bool IsListeningSocket() const { return true; } | |
363 | |
364 virtual bool SetPortAndMask(Dart_Port port, intptr_t mask) { | |
365 bool was_empty = !active_readers_.HasHead(); | |
366 HashMap::Entry* entry = tokens_map_.Lookup( | |
367 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), true); | |
368 PortEntry* pentry; | |
369 if (entry->value == NULL) { | |
370 pentry = new PortEntry(); | |
371 pentry->dart_port = port; | |
372 pentry->token_count = kTokenCount; | |
373 pentry->is_reading = IsReadingMask(mask); | |
374 entry->value = reinterpret_cast<void*>(pentry); | |
375 | |
376 if (pentry->IsReady()) { | |
377 active_readers_.Add(pentry); | |
378 } | |
379 } else { | |
380 pentry = reinterpret_cast<PortEntry*>(entry->value); | |
381 bool was_ready = pentry->IsReady(); | |
382 pentry->is_reading = IsReadingMask(mask); | |
383 bool is_ready = pentry->IsReady(); | |
384 | |
385 if (was_ready && !is_ready) { | |
386 active_readers_.Remove(pentry); | |
387 } else if (!was_ready && is_ready) { | |
388 active_readers_.Add(pentry); | |
389 } | |
390 } | |
391 | |
392 #ifdef DEBUG | |
393 // To ensure that all readers are ready. | |
394 PortEntry* root = reinterpret_cast<PortEntry*>(active_readers_.head()); | |
395 | |
396 int ready_count = 0; | |
397 if (root != NULL) { | |
398 PortEntry* current = root; | |
399 do { | |
400 ASSERT(current->IsReady()); | |
401 ready_count++; | |
402 active_readers_.Rotate(); | |
403 current = active_readers_.head(); | |
404 } while (current != root); | |
405 } | |
406 for (HashMap::Entry *entry = tokens_map_.Start(); | |
407 entry != NULL; | |
408 entry = tokens_map_.Next(entry)) { | |
409 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
410 if (pentry->IsReady()) { | |
411 ready_count--; | |
412 } | |
413 } | |
414 // Ensure all ready items are in `active_readers_`. | |
415 ASSERT(ready_count == 0); | |
416 #endif | |
417 | |
418 return was_empty && active_readers_.HasHead(); | |
419 } | |
420 | |
421 virtual bool RemovePort(Dart_Port port) { | |
422 HashMap::Entry* entry = tokens_map_.Lookup( | |
423 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); | |
424 if (entry != NULL) { | |
425 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
426 if (pentry->IsReady()) { | |
427 active_readers_.Remove(pentry); | |
428 } | |
429 tokens_map_.Remove( | |
430 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port)); | |
431 delete pentry; | |
432 } else { | |
433 // NOTE: This is a listening socket which has been immediately closed. | |
434 // | |
435 // If a listening socket is not listened on, the event handler does not | |
436 // know about it beforehand. So the first time the event handler knows | |
437 // about it, is when it is supposed to be closed. We therefore do nothing | |
438 // here. | |
439 // | |
440 // But whether to close it, depends on whether other isolates have it open | |
441 // as well or not. | |
442 } | |
443 return !active_readers_.HasHead(); | |
444 } | |
445 | |
446 virtual Dart_Port NextPort() { | |
447 ASSERT(active_readers_.HasHead()); | |
448 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head()); | |
449 return pentry->dart_port; | |
450 } | |
451 | |
452 virtual bool HasNextPort() { | |
453 return active_readers_.HasHead(); | |
454 } | |
455 | |
456 virtual void SendToAll(uintptr_t data) { | |
457 for (HashMap::Entry *entry = tokens_map_.Start(); | |
458 entry != NULL; | |
459 entry = tokens_map_.Next(entry)) { | |
460 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
461 DartUtils::PostInt32(pentry->dart_port, data); | |
462 } | |
463 } | |
464 | |
465 | |
466 virtual bool TakeToken() { | |
467 ASSERT(active_readers_.HasHead()); | |
468 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head()); | |
469 ASSERT(pentry->token_count > 0); | |
470 pentry->token_count--; | |
471 if (pentry->token_count == 0) { | |
472 active_readers_.RemoveHead(); | |
473 return !active_readers_.HasHead(); | |
474 } else { | |
475 active_readers_.Rotate(); | |
476 return false; | |
477 } | |
478 } | |
479 | |
480 virtual bool ReturnTokens(Dart_Port port, int count) { | |
481 HashMap::Entry* entry = tokens_map_.Lookup( | |
482 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); | |
483 ASSERT(entry != NULL); | |
484 | |
485 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
486 pentry->token_count += count; | |
487 if (pentry->token_count == count && pentry->IsReady()) { | |
488 bool was_empty = !active_readers_.HasHead(); | |
489 active_readers_.Add(pentry); | |
490 return was_empty; | |
491 } | |
492 return false; | |
493 } | |
494 | |
495 virtual bool HasTokens() const { | |
496 return active_readers_.HasHead(); | |
497 } | |
498 | |
499 virtual intptr_t Mask() { | |
500 if (active_readers_.HasHead()) { | |
501 return 1 << kInEvent; | |
502 } | |
503 return 0; | |
504 } | |
505 | |
506 virtual void Close() { | |
507 SI::Close(); | |
508 } | |
509 | |
510 private: | |
511 // The [Dart_Port]s which are not paused (i.e. are interested in read events, | |
512 // i.e. `mask == (1 << kInEvent)`) and we have enough tokens to communicate | |
513 // with them. | |
514 CircularLinkedList<PortEntry *> active_readers_; | |
515 | |
516 // A convenience mapping: | |
517 // Dart_Port -> struct PortEntry { dart_port, mask, token_count } | |
518 HashMap tokens_map_; | |
519 }; | |
520 | |
521 | |
522 class InterruptMessage { | |
523 public: | |
524 intptr_t id; | |
525 Dart_Port dart_port; | |
526 int64_t data; | |
527 }; | |
528 | |
529 | |
530 static const int kInterruptMessageSize = sizeof(InterruptMessage); | |
531 static const int kInfinityTimeout = -1; | |
532 static const int kTimerId = -1; | |
533 static const int kShutdownId = -2; | |
534 | |
535 } // namespace bin | 97 } // namespace bin |
536 } // namespace dart | 98 } // namespace dart |
537 | 99 |
538 // The event handler delegation class is OS specific. | 100 // The event handler delegation class is OS specific. |
539 #if defined(TARGET_OS_ANDROID) | 101 #if defined(TARGET_OS_ANDROID) |
540 #include "bin/eventhandler_android.h" | 102 #include "bin/eventhandler_android.h" |
541 #elif defined(TARGET_OS_LINUX) | 103 #elif defined(TARGET_OS_LINUX) |
542 #include "bin/eventhandler_linux.h" | 104 #include "bin/eventhandler_linux.h" |
543 #elif defined(TARGET_OS_MACOS) | 105 #elif defined(TARGET_OS_MACOS) |
544 #include "bin/eventhandler_macos.h" | 106 #include "bin/eventhandler_macos.h" |
(...skipping 27 matching lines...) Expand all Loading... |
572 | 134 |
573 private: | 135 private: |
574 friend class EventHandlerImplementation; | 136 friend class EventHandlerImplementation; |
575 EventHandlerImplementation delegate_; | 137 EventHandlerImplementation delegate_; |
576 }; | 138 }; |
577 | 139 |
578 } // namespace bin | 140 } // namespace bin |
579 } // namespace dart | 141 } // namespace dart |
580 | 142 |
581 #endif // BIN_EVENTHANDLER_H_ | 143 #endif // BIN_EVENTHANDLER_H_ |
OLD | NEW |