Chromium Code Reviews| 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" | |
| 9 #include "bin/isolate_data.h" | 10 #include "bin/isolate_data.h" |
| 10 | 11 |
| 12 #include "platform/hashmap.h" | |
| 13 | |
| 11 namespace dart { | 14 namespace dart { |
| 12 namespace bin { | 15 namespace bin { |
| 13 | 16 |
| 14 // Flags used to provide information and actions to the eventhandler | 17 // Flags used to provide information and actions to the eventhandler |
| 15 // when sending a message about a file descriptor. These flags should | 18 // 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 | 19 // be kept in sync with the constants in socket_impl.dart. For more |
| 17 // information see the comments in socket_impl.dart | 20 // information see the comments in socket_impl.dart |
| 18 enum MessageFlags { | 21 enum MessageFlags { |
| 19 kInEvent = 0, | 22 kInEvent = 0, |
| 20 kOutEvent = 1, | 23 kOutEvent = 1, |
| 21 kErrorEvent = 2, | 24 kErrorEvent = 2, |
| 22 kCloseEvent = 3, | 25 kCloseEvent = 3, |
| 23 kDestroyedEvent = 4, | 26 kDestroyedEvent = 4, |
| 24 kCloseCommand = 8, | 27 kCloseCommand = 8, |
| 25 kShutdownReadCommand = 9, | 28 kShutdownReadCommand = 9, |
| 26 kShutdownWriteCommand = 10, | 29 kShutdownWriteCommand = 10, |
| 27 kReturnTokenCommand = 11, | 30 kReturnTokenCommand = 11, |
| 28 kListeningSocket = 16, | 31 kListeningSocket = 16, |
| 29 kPipe = 17, | 32 kPipe = 17, |
| 30 }; | 33 }; |
| 31 | 34 |
| 35 #define EVENT_MASK ((1 << kInEvent) | \ | |
| 36 (1 << kOutEvent) | \ | |
| 37 (1 << kErrorEvent) | \ | |
| 38 (1 << kCloseEvent) | \ | |
| 39 (1 << kDestroyedEvent)) | |
| 32 #define COMMAND_MASK ((1 << kCloseCommand) | \ | 40 #define COMMAND_MASK ((1 << kCloseCommand) | \ |
| 33 (1 << kShutdownReadCommand) | \ | 41 (1 << kShutdownReadCommand) | \ |
| 34 (1 << kShutdownWriteCommand) | \ | 42 (1 << kShutdownWriteCommand) | \ |
| 35 (1 << kReturnTokenCommand)) | 43 (1 << kReturnTokenCommand)) |
| 36 #define IS_COMMAND(data, command_bit) \ | 44 #define IS_COMMAND(data, command_bit) \ |
| 37 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT | 45 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT |
| 38 #define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0) // NOLINT | 46 #define ASSERT_NO_COMMAND(data) ASSERT((data & COMMAND_MASK) == 0) // NOLINT |
| 39 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) | 47 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) |
| 40 | 48 |
| 41 class TimeoutQueue { | 49 class TimeoutQueue { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 UpdateTimeout(CurrentPort(), -1); | 95 UpdateTimeout(CurrentPort(), -1); |
| 88 } | 96 } |
| 89 | 97 |
| 90 void UpdateTimeout(Dart_Port port, int64_t timeout); | 98 void UpdateTimeout(Dart_Port port, int64_t timeout); |
| 91 | 99 |
| 92 private: | 100 private: |
| 93 Timeout* next_timeout_; | 101 Timeout* next_timeout_; |
| 94 Timeout* timeouts_; | 102 Timeout* timeouts_; |
| 95 }; | 103 }; |
| 96 | 104 |
| 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 } | |
|
Søren Gjesse
2015/02/04 12:19:57
Maybe have an #ifdef DEBUG section checking that a
kustermann
2015/02/04 13:39:42
Done.
| |
| 390 } | |
| 391 | |
| 392 return was_empty && active_readers_.HasHead(); | |
| 393 } | |
| 394 | |
| 395 virtual bool RemovePort(Dart_Port port) { | |
| 396 HashMap::Entry* entry = tokens_map_.Lookup( | |
| 397 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); | |
| 398 if (entry != NULL) { | |
| 399 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
| 400 if (pentry->IsReady()) { | |
| 401 active_readers_.Remove(pentry); | |
| 402 } | |
| 403 tokens_map_.Remove( | |
| 404 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port)); | |
| 405 delete pentry; | |
| 406 } else { | |
| 407 // NOTE: This is a listening socket which has been immediately closed. | |
| 408 // | |
| 409 // If a listening socket is not listened on, the event handler does not | |
| 410 // know about it beforehand. So the first time the event handler knows | |
| 411 // about it, is when it is supposed to be closed. We therefore do nothing | |
| 412 // here. | |
| 413 // | |
| 414 // But whether to close it, depends on whether other isolates have it open | |
| 415 // as well or not. | |
| 416 } | |
| 417 return !active_readers_.HasHead(); | |
| 418 } | |
| 419 | |
| 420 virtual Dart_Port NextPort() { | |
| 421 ASSERT(active_readers_.HasHead()); | |
| 422 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head()); | |
| 423 return pentry->dart_port; | |
| 424 } | |
| 425 | |
| 426 virtual bool HasNextPort() { | |
| 427 return active_readers_.HasHead(); | |
| 428 } | |
| 429 | |
| 430 virtual void SendToAll(uintptr_t data) { | |
| 431 for (HashMap::Entry *entry = tokens_map_.Start(); | |
| 432 entry != NULL; | |
| 433 entry = tokens_map_.Next(entry)) { | |
| 434 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
| 435 DartUtils::PostInt32(pentry->dart_port, data); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 | |
| 440 virtual bool TakeToken() { | |
| 441 ASSERT(active_readers_.HasHead()); | |
| 442 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head()); | |
| 443 ASSERT(pentry->token_count > 0); | |
| 444 pentry->token_count--; | |
| 445 if (pentry->token_count == 0) { | |
| 446 active_readers_.RemoveHead(); | |
| 447 return !active_readers_.HasHead(); | |
| 448 } else { | |
| 449 active_readers_.Rotate(); | |
| 450 return false; | |
| 451 } | |
| 452 } | |
| 453 | |
| 454 virtual bool ReturnTokens(Dart_Port port, int count) { | |
| 455 HashMap::Entry* entry = tokens_map_.Lookup( | |
| 456 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); | |
| 457 ASSERT(entry != NULL); | |
| 458 | |
| 459 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); | |
| 460 pentry->token_count += count; | |
| 461 if (pentry->token_count == count && pentry->IsReady()) { | |
| 462 bool was_empty = !active_readers_.HasHead(); | |
| 463 active_readers_.Add(pentry); | |
| 464 return was_empty; | |
| 465 } | |
| 466 return false; | |
| 467 } | |
| 468 | |
| 469 virtual bool HasTokens() const { | |
| 470 return active_readers_.HasHead(); | |
| 471 } | |
| 472 | |
| 473 virtual intptr_t Mask() { | |
| 474 if (active_readers_.HasHead()) { | |
| 475 return 1 << kInEvent; | |
| 476 } | |
| 477 return 0; | |
| 478 } | |
| 479 | |
| 480 virtual void Close() { | |
| 481 SI::Close(); | |
| 482 } | |
| 483 | |
| 484 private: | |
| 485 // The [Dart_Port]s which are not paused (i.e. are interested in read events, | |
| 486 // i.e. `mask == (1 << kInEvent)`) and we have enough tokens to communicate | |
| 487 // with them. | |
| 488 CircularLinkedList<PortEntry *> active_readers_; | |
| 489 | |
| 490 // A convenience mapping: | |
| 491 // Dart_Port -> struct PortEntry { dart_port, mask, token_count } | |
| 492 HashMap tokens_map_; | |
| 493 }; | |
| 494 | |
| 495 | |
| 496 class InterruptMessage { | |
| 497 public: | |
| 498 intptr_t id; | |
| 499 Dart_Port dart_port; | |
| 500 int64_t data; | |
| 501 }; | |
| 502 | |
| 503 | |
| 504 static const int kInterruptMessageSize = sizeof(InterruptMessage); | |
| 505 static const int kInfinityTimeout = -1; | |
| 506 static const int kTimerId = -1; | |
| 507 static const int kShutdownId = -2; | |
| 508 | |
| 97 } // namespace bin | 509 } // namespace bin |
| 98 } // namespace dart | 510 } // namespace dart |
| 99 | 511 |
| 100 // The event handler delegation class is OS specific. | 512 // The event handler delegation class is OS specific. |
| 101 #if defined(TARGET_OS_ANDROID) | 513 #if defined(TARGET_OS_ANDROID) |
| 102 #include "bin/eventhandler_android.h" | 514 #include "bin/eventhandler_android.h" |
| 103 #elif defined(TARGET_OS_LINUX) | 515 #elif defined(TARGET_OS_LINUX) |
| 104 #include "bin/eventhandler_linux.h" | 516 #include "bin/eventhandler_linux.h" |
| 105 #elif defined(TARGET_OS_MACOS) | 517 #elif defined(TARGET_OS_MACOS) |
| 106 #include "bin/eventhandler_macos.h" | 518 #include "bin/eventhandler_macos.h" |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 134 | 546 |
| 135 private: | 547 private: |
| 136 friend class EventHandlerImplementation; | 548 friend class EventHandlerImplementation; |
| 137 EventHandlerImplementation delegate_; | 549 EventHandlerImplementation delegate_; |
| 138 }; | 550 }; |
| 139 | 551 |
| 140 } // namespace bin | 552 } // namespace bin |
| 141 } // namespace dart | 553 } // namespace dart |
| 142 | 554 |
| 143 #endif // BIN_EVENTHANDLER_H_ | 555 #endif // BIN_EVENTHANDLER_H_ |
| OLD | NEW |