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