| 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, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 37 (1 << kSetEventMaskCommand)) | 40 (1 << kSetEventMaskCommand)) |
| 38 #define EVENT_MASK ((1 << kInEvent) | \ | 41 #define EVENT_MASK ((1 << kInEvent) | \ |
| 39 (1 << kOutEvent) | \ | 42 (1 << kOutEvent) | \ |
| 40 (1 << kErrorEvent) | \ | 43 (1 << kErrorEvent) | \ |
| 41 (1 << kCloseEvent) | \ | 44 (1 << kCloseEvent) | \ |
| 42 (1 << kDestroyedEvent)) | 45 (1 << kDestroyedEvent)) |
| 43 #define IS_COMMAND(data, command_bit) \ | 46 #define IS_COMMAND(data, command_bit) \ |
| 44 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT | 47 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT |
| 45 #define IS_EVENT(data, event_bit) \ | 48 #define IS_EVENT(data, event_bit) \ |
| 46 ((data & EVENT_MASK) == (1 << event_bit)) // NOLINT | 49 ((data & EVENT_MASK) == (1 << event_bit)) // NOLINT |
| 50 #define IS_IO_EVENT(data) \ |
| 51 ((data & (1 << kInEvent | 1 << kOutEvent | 1 << kCloseEvent)) != 0 && \ |
| 52 (data & ~(1 << kInEvent | 1 << kOutEvent | 1 << kCloseEvent)) == 0) |
| 47 #define IS_LISTENING_SOCKET(data) \ | 53 #define IS_LISTENING_SOCKET(data) \ |
| 48 ((data & (1 << kListeningSocket)) != 0) // NOLINT | 54 ((data & (1 << kListeningSocket)) != 0) // NOLINT |
| 49 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) | 55 #define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1)) |
| 50 | 56 |
| 51 class TimeoutQueue { | 57 class TimeoutQueue { |
| 52 private: | 58 private: |
| 53 class Timeout { | 59 class Timeout { |
| 54 public: | 60 public: |
| 55 Timeout(Dart_Port port, int64_t timeout, Timeout* next) | 61 Timeout(Dart_Port port, int64_t timeout, Timeout* next) |
| 56 : port_(port), timeout_(timeout), next_(next) {} | 62 : port_(port), timeout_(timeout), next_(next) {} |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 if (e->next_ == e) { | 154 if (e->next_ == e) { |
| 149 head_ = NULL; | 155 head_ = NULL; |
| 150 } else { | 156 } else { |
| 151 e->prev_->next_ = e->next_; | 157 e->prev_->next_ = e->next_; |
| 152 e->next_->prev_ = e->prev_; | 158 e->next_->prev_ = e->prev_; |
| 153 head_ = e->next_; | 159 head_ = e->next_; |
| 154 } | 160 } |
| 155 delete e; | 161 delete e; |
| 156 } | 162 } |
| 157 | 163 |
| 164 void Remove(T item) { |
| 165 if (head_ == NULL) { |
| 166 return; |
| 167 } else if (head_ == head_->next_) { |
| 168 if (head_->t == item) { |
| 169 delete head_; |
| 170 head_ = NULL; |
| 171 return; |
| 172 } |
| 173 } else { |
| 174 Entry *current = head_; |
| 175 do { |
| 176 if (current->t == item) { |
| 177 Entry *next = current->next_; |
| 178 Entry *prev = current->prev_; |
| 179 prev->next_ = next; |
| 180 next->prev_ = prev; |
| 181 delete current; |
| 182 return; |
| 183 } |
| 184 current = current->next_; |
| 185 } while (current != head_); |
| 186 } |
| 187 } |
| 188 |
| 189 |
| 158 T head() const { return head_->t; } | 190 T head() const { return head_->t; } |
| 159 | 191 |
| 160 bool HasHead() { | 192 bool HasHead() const { |
| 161 return head_ != NULL; | 193 return head_ != NULL; |
| 162 } | 194 } |
| 163 | 195 |
| 164 void Rotate() { | 196 void Rotate() { |
| 165 head_ = head_->next_; | 197 if (head_ != NULL) { |
| 198 ASSERT(head_->next_ != NULL); |
| 199 head_ = head_->next_; |
| 200 } |
| 166 } | 201 } |
| 167 | 202 |
| 168 private: | 203 private: |
| 169 struct Entry { | 204 struct Entry { |
| 170 explicit Entry(const T& t) : t(t) {} | 205 explicit Entry(const T& t) : t(t) {} |
| 171 const T t; | 206 const T t; |
| 172 Entry* next_; | 207 Entry* next_; |
| 173 Entry* prev_; | 208 Entry* prev_; |
| 174 }; | 209 }; |
| 175 | 210 |
| 176 Entry* head_; | 211 Entry* head_; |
| 177 }; | 212 }; |
| 178 | 213 |
| 214 |
| 215 class DescriptorInfoBase { |
| 216 public: |
| 217 explicit DescriptorInfoBase(intptr_t fd) : fd_(fd) { |
| 218 ASSERT(fd_ != -1); |
| 219 } |
| 220 |
| 221 virtual ~DescriptorInfoBase() {} |
| 222 |
| 223 // The OS descriptor. |
| 224 intptr_t fd() { return fd_; } |
| 225 |
| 226 // Whether this descriptor refers to an underlying listening OS socket. |
| 227 virtual bool IsListeningSocket() const = 0; |
| 228 |
| 229 // Inserts or updates a new Dart_Port which is interested in events specified |
| 230 // in `mask`. |
| 231 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) = 0; |
| 232 |
| 233 // Removes a port from the interested listeners. |
| 234 virtual void RemovePort(Dart_Port port) = 0; |
| 235 |
| 236 // Returns a port to which `events_ready` can be sent to. It will also |
| 237 // decrease the token count by 1 for this port. |
| 238 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) = 0; |
| 239 |
| 240 // Will post `data` to all known Dart_Ports. It will also decrease the token |
| 241 // count by 1 for all ports. |
| 242 virtual void NotifyAllDartPorts(uintptr_t events) = 0; |
| 243 |
| 244 // Returns `count` tokens for the given port. |
| 245 virtual void ReturnTokens(Dart_Port port, int count) = 0; |
| 246 |
| 247 // Returns the union of event masks of all ports. If a port has a non-positive |
| 248 // token count it's mask is assumed to be 0. |
| 249 virtual intptr_t Mask() = 0; |
| 250 |
| 251 // Closes this descriptor. |
| 252 virtual void Close() = 0; |
| 253 |
| 254 protected: |
| 255 intptr_t fd_; |
| 256 }; |
| 257 |
| 258 |
| 259 // Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on |
| 260 // windows) which is connected to a single Dart_Port. |
| 261 // |
| 262 // Subclasses of this class can be e.g. connected tcp sockets. |
| 263 template<typename DI> |
| 264 class DescriptorInfoSingleMixin : public DI { |
| 265 private: |
| 266 static const int kTokenCount = 16; |
| 267 |
| 268 public: |
| 269 explicit DescriptorInfoSingleMixin(intptr_t fd) |
| 270 : DI(fd), port_(0), tokens_(kTokenCount), mask_(0) {} |
| 271 |
| 272 virtual ~DescriptorInfoSingleMixin() { } |
| 273 |
| 274 virtual bool IsListeningSocket() const { return false; } |
| 275 |
| 276 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) { |
| 277 ASSERT(port_ == 0 || port == port_); |
| 278 port_ = port; |
| 279 mask_ = mask; |
| 280 } |
| 281 |
| 282 virtual void RemovePort(Dart_Port port) { |
| 283 // TODO(dart:io): Find out where we call RemovePort() with the invalid |
| 284 // port. Afterwards remove the part in the ASSERT here. |
| 285 ASSERT(port_ == 0 || port_ == port); |
| 286 port_ = 0; |
| 287 mask_ = 0; |
| 288 } |
| 289 |
| 290 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) { |
| 291 ASSERT(IS_IO_EVENT(events_ready) || |
| 292 IS_EVENT(events_ready, kDestroyedEvent)); |
| 293 tokens_--; |
| 294 return port_; |
| 295 } |
| 296 |
| 297 virtual void NotifyAllDartPorts(uintptr_t events) { |
| 298 // Unexpected close or error events are the only ones we broadcast to all |
| 299 // listeners and are the only ones where we do not count tokens. |
| 300 ASSERT(IS_EVENT(events, kCloseEvent) || |
| 301 IS_EVENT(events, kErrorEvent)); |
| 302 |
| 303 if (port_ != 0) { |
| 304 DartUtils::PostInt32(port_, events); |
| 305 } |
| 306 tokens_--; |
| 307 } |
| 308 |
| 309 virtual void ReturnTokens(Dart_Port port, int count) { |
| 310 ASSERT(port_ == port); |
| 311 ASSERT(tokens_ >= 0); |
| 312 tokens_ += count; |
| 313 ASSERT(tokens_ <= kTokenCount); |
| 314 } |
| 315 |
| 316 virtual intptr_t Mask() { |
| 317 if (tokens_ <= 0) { |
| 318 return 0; |
| 319 } |
| 320 return mask_; |
| 321 } |
| 322 |
| 323 virtual void Close() { |
| 324 DI::Close(); |
| 325 } |
| 326 |
| 327 private: |
| 328 Dart_Port port_; |
| 329 int tokens_; |
| 330 intptr_t mask_; |
| 331 }; |
| 332 |
| 333 |
| 334 // Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on |
| 335 // windows) which is connected to multiple Dart_Port's. |
| 336 // |
| 337 // Subclasses of this class can be e.g. a listening socket which multiple |
| 338 // isolates are listening on. |
| 339 template<typename DI> |
| 340 class DescriptorInfoMultipleMixin : public DI { |
| 341 private: |
| 342 static const int kTokenCount = 4; |
| 343 |
| 344 static bool SamePortValue(void* key1, void* key2) { |
| 345 return reinterpret_cast<Dart_Port>(key1) == |
| 346 reinterpret_cast<Dart_Port>(key2); |
| 347 } |
| 348 |
| 349 static uint32_t GetHashmapHashFromPort(Dart_Port port) { |
| 350 return static_cast<uint32_t>(port & 0xFFFFFFFF); |
| 351 } |
| 352 |
| 353 static void* GetHashmapKeyFromPort(Dart_Port port) { |
| 354 return reinterpret_cast<void*>(port); |
| 355 } |
| 356 |
| 357 static bool IsReadingMask(intptr_t mask) { |
| 358 if (mask == (1 << kInEvent)) { |
| 359 return true; |
| 360 } else { |
| 361 ASSERT(mask == 0); |
| 362 return false; |
| 363 } |
| 364 } |
| 365 |
| 366 struct PortEntry { |
| 367 Dart_Port dart_port; |
| 368 intptr_t is_reading; |
| 369 intptr_t token_count; |
| 370 |
| 371 bool IsReady() { return token_count > 0 && is_reading; } |
| 372 }; |
| 373 |
| 374 public: |
| 375 explicit DescriptorInfoMultipleMixin(intptr_t fd) |
| 376 : DI(fd), tokens_map_(&SamePortValue, kTokenCount) {} |
| 377 |
| 378 virtual ~DescriptorInfoMultipleMixin() {} |
| 379 |
| 380 virtual bool IsListeningSocket() const { return true; } |
| 381 |
| 382 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) { |
| 383 HashMap::Entry* entry = tokens_map_.Lookup( |
| 384 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), true); |
| 385 PortEntry* pentry; |
| 386 if (entry->value == NULL) { |
| 387 pentry = new PortEntry(); |
| 388 pentry->dart_port = port; |
| 389 pentry->token_count = kTokenCount; |
| 390 pentry->is_reading = IsReadingMask(mask); |
| 391 entry->value = reinterpret_cast<void*>(pentry); |
| 392 |
| 393 if (pentry->IsReady()) { |
| 394 active_readers_.Add(pentry); |
| 395 } |
| 396 } else { |
| 397 pentry = reinterpret_cast<PortEntry*>(entry->value); |
| 398 bool was_ready = pentry->IsReady(); |
| 399 pentry->is_reading = IsReadingMask(mask); |
| 400 bool is_ready = pentry->IsReady(); |
| 401 |
| 402 if (was_ready && !is_ready) { |
| 403 active_readers_.Remove(pentry); |
| 404 } else if (!was_ready && is_ready) { |
| 405 active_readers_.Add(pentry); |
| 406 } |
| 407 } |
| 408 |
| 409 #ifdef DEBUG |
| 410 // To ensure that all readers are ready. |
| 411 PortEntry* root = reinterpret_cast<PortEntry*>(active_readers_.head()); |
| 412 |
| 413 int ready_count = 0; |
| 414 if (root != NULL) { |
| 415 PortEntry* current = root; |
| 416 do { |
| 417 ASSERT(current->IsReady()); |
| 418 ready_count++; |
| 419 active_readers_.Rotate(); |
| 420 current = active_readers_.head(); |
| 421 } while (current != root); |
| 422 } |
| 423 for (HashMap::Entry *entry = tokens_map_.Start(); |
| 424 entry != NULL; |
| 425 entry = tokens_map_.Next(entry)) { |
| 426 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); |
| 427 if (pentry->IsReady()) { |
| 428 ready_count--; |
| 429 } |
| 430 } |
| 431 // Ensure all ready items are in `active_readers_`. |
| 432 ASSERT(ready_count == 0); |
| 433 #endif |
| 434 } |
| 435 |
| 436 virtual void RemovePort(Dart_Port port) { |
| 437 HashMap::Entry* entry = tokens_map_.Lookup( |
| 438 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); |
| 439 if (entry != NULL) { |
| 440 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); |
| 441 if (pentry->IsReady()) { |
| 442 active_readers_.Remove(pentry); |
| 443 } |
| 444 tokens_map_.Remove( |
| 445 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port)); |
| 446 delete pentry; |
| 447 } else { |
| 448 // NOTE: This is a listening socket which has been immediately closed. |
| 449 // |
| 450 // If a listening socket is not listened on, the event handler does not |
| 451 // know about it beforehand. So the first time the event handler knows |
| 452 // about it, is when it is supposed to be closed. We therefore do nothing |
| 453 // here. |
| 454 // |
| 455 // But whether to close it, depends on whether other isolates have it open |
| 456 // as well or not. |
| 457 } |
| 458 } |
| 459 |
| 460 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) { |
| 461 // We're only sending `kInEvents` if there are multiple listeners (which is |
| 462 // listening socktes). |
| 463 ASSERT(IS_EVENT(events_ready, kInEvent) || |
| 464 IS_EVENT(events_ready, kDestroyedEvent)); |
| 465 |
| 466 if (active_readers_.HasHead()) { |
| 467 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head()); |
| 468 |
| 469 // Update token count. |
| 470 pentry->token_count--; |
| 471 if (pentry->token_count <= 0) { |
| 472 active_readers_.RemoveHead(); |
| 473 } else { |
| 474 active_readers_.Rotate(); |
| 475 } |
| 476 |
| 477 return pentry->dart_port; |
| 478 } |
| 479 return 0; |
| 480 } |
| 481 |
| 482 virtual void NotifyAllDartPorts(uintptr_t events) { |
| 483 // Unexpected close or error events are the only ones we broadcast to all |
| 484 // listeners and are the only ones where we do not count tokens. |
| 485 ASSERT(IS_EVENT(events, kCloseEvent) || |
| 486 IS_EVENT(events, kErrorEvent)); |
| 487 |
| 488 for (HashMap::Entry *entry = tokens_map_.Start(); |
| 489 entry != NULL; |
| 490 entry = tokens_map_.Next(entry)) { |
| 491 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); |
| 492 DartUtils::PostInt32(pentry->dart_port, events); |
| 493 |
| 494 // Update token count. |
| 495 bool was_ready = pentry->IsReady(); |
| 496 pentry->token_count--; |
| 497 |
| 498 if (was_ready && pentry->token_count <= 0) { |
| 499 active_readers_.Remove(pentry); |
| 500 } |
| 501 } |
| 502 } |
| 503 |
| 504 virtual void ReturnTokens(Dart_Port port, int count) { |
| 505 HashMap::Entry* entry = tokens_map_.Lookup( |
| 506 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false); |
| 507 ASSERT(entry != NULL); |
| 508 |
| 509 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value); |
| 510 bool was_ready = pentry->IsReady(); |
| 511 ASSERT(pentry->token_count >= 0); |
| 512 pentry->token_count += count; |
| 513 ASSERT(pentry->token_count <= kTokenCount); |
| 514 bool is_ready = pentry->token_count > 0 && pentry->IsReady(); |
| 515 if (!was_ready && is_ready) { |
| 516 active_readers_.Add(pentry); |
| 517 } |
| 518 } |
| 519 |
| 520 virtual intptr_t Mask() { |
| 521 if (active_readers_.HasHead()) { |
| 522 return 1 << kInEvent; |
| 523 } |
| 524 return 0; |
| 525 } |
| 526 |
| 527 virtual void Close() { |
| 528 DI::Close(); |
| 529 } |
| 530 |
| 531 private: |
| 532 // The [Dart_Port]s which are not paused (i.e. are interested in read events, |
| 533 // i.e. `mask == (1 << kInEvent)`) and we have enough tokens to communicate |
| 534 // with them. |
| 535 CircularLinkedList<PortEntry *> active_readers_; |
| 536 |
| 537 // A convenience mapping: |
| 538 // Dart_Port -> struct PortEntry { dart_port, mask, token_count } |
| 539 HashMap tokens_map_; |
| 540 }; |
| 541 |
| 542 |
| 179 } // namespace bin | 543 } // namespace bin |
| 180 } // namespace dart | 544 } // namespace dart |
| 181 | 545 |
| 182 // The event handler delegation class is OS specific. | 546 // The event handler delegation class is OS specific. |
| 183 #if defined(TARGET_OS_ANDROID) | 547 #if defined(TARGET_OS_ANDROID) |
| 184 #include "bin/eventhandler_android.h" | 548 #include "bin/eventhandler_android.h" |
| 185 #elif defined(TARGET_OS_LINUX) | 549 #elif defined(TARGET_OS_LINUX) |
| 186 #include "bin/eventhandler_linux.h" | 550 #include "bin/eventhandler_linux.h" |
| 187 #elif defined(TARGET_OS_MACOS) | 551 #elif defined(TARGET_OS_MACOS) |
| 188 #include "bin/eventhandler_macos.h" | 552 #include "bin/eventhandler_macos.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 | 585 |
| 222 private: | 586 private: |
| 223 friend class EventHandlerImplementation; | 587 friend class EventHandlerImplementation; |
| 224 EventHandlerImplementation delegate_; | 588 EventHandlerImplementation delegate_; |
| 225 }; | 589 }; |
| 226 | 590 |
| 227 } // namespace bin | 591 } // namespace bin |
| 228 } // namespace dart | 592 } // namespace dart |
| 229 | 593 |
| 230 #endif // BIN_EVENTHANDLER_H_ | 594 #endif // BIN_EVENTHANDLER_H_ |
| OLD | NEW |