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