Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
eventhandler.h
Go to the documentation of this 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
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_BIN_EVENTHANDLER_H_
6#define RUNTIME_BIN_EVENTHANDLER_H_
7
8#include "bin/builtin.h"
9#include "bin/dartutils.h"
10#include "bin/isolate_data.h"
11
12#include "platform/hashmap.h"
14
15namespace dart {
16namespace bin {
17
18// Flags used to provide information and actions to the eventhandler
19// when sending a message about a file descriptor. These flags should
20// be kept in sync with the constants in socket_patch.dart. For more
21// information see the comments in socket_patch.dart
37
38// clang-format off
39#define COMMAND_MASK ((1 << kCloseCommand) | \
40 (1 << kShutdownReadCommand) | \
41 (1 << kShutdownWriteCommand) | \
42 (1 << kReturnTokenCommand) | \
43 (1 << kSetEventMaskCommand))
44#define EVENT_MASK ((1 << kInEvent) | \
45 (1 << kOutEvent) | \
46 (1 << kErrorEvent) | \
47 (1 << kCloseEvent) | \
48 (1 << kDestroyedEvent))
49#define IS_COMMAND(data, command_bit) \
50 ((data & COMMAND_MASK) == (1 << command_bit)) // NOLINT
51#define IS_EVENT(data, event_bit) \
52 ((data & EVENT_MASK) == (1 << event_bit)) // NOLINT
53#define IS_IO_EVENT(data) \
54 ((data & (1 << kInEvent | 1 << kOutEvent | 1 << kCloseEvent)) != 0 && \
55 (data & ~(1 << kInEvent | 1 << kOutEvent | 1 << kCloseEvent)) == 0)
56#define IS_LISTENING_SOCKET(data) \
57 ((data & (1 << kListeningSocket)) != 0) // NOLINT
58#define IS_SIGNAL_SOCKET(data) \
59 ((data & (1 << kSignalSocket)) != 0) // NOLINT
60#define TOKEN_COUNT(data) (data & ((1 << kCloseCommand) - 1))
61// clang-format on
62
64 public:
66
68 while (HasTimeout())
70 }
71
72 bool HasTimeout() const { return !timeouts_.IsEmpty(); }
73
74 int64_t CurrentTimeout() const {
75 ASSERT(!timeouts_.IsEmpty());
76 return timeouts_.Minimum().priority;
77 }
78
80 ASSERT(!timeouts_.IsEmpty());
81 return timeouts_.Minimum().value;
82 }
83
84 void RemoveCurrent() { timeouts_.RemoveMinimum(); }
85
86 void UpdateTimeout(Dart_Port port, int64_t timeout) {
87 if (timeout < 0) {
88 timeouts_.RemoveByValue(port);
89 } else {
90 timeouts_.InsertOrChangePriority(timeout, port);
91 }
92 }
93
94 private:
96
98};
99
101 public:
102 intptr_t id;
104 int64_t data;
105};
106
107static constexpr intptr_t kInterruptMessageSize = sizeof(InterruptMessage);
108static constexpr intptr_t kInfinityTimeout = -1;
109static constexpr intptr_t kTimerId = -1;
110static constexpr intptr_t kShutdownId = -2;
111
112template <typename T>
114 public:
115 CircularLinkedList() : head_(nullptr) {}
116
117 typedef void (*ClearFun)(void* value);
118
119 // Returns true if the list was empty.
120 bool Add(T t) {
121 Entry* e = new Entry(t);
122 if (head_ == nullptr) {
123 // Empty list, make e head, and point to itself.
124 e->next_ = e;
125 e->prev_ = e;
126 head_ = e;
127 return true;
128 } else {
129 // Insert e as the last element in the list.
130 e->prev_ = head_->prev_;
131 e->next_ = head_;
132 e->prev_->next_ = e;
133 head_->prev_ = e;
134 return false;
135 }
136 }
137
138 void RemoveHead(ClearFun clear = nullptr) {
139 ASSERT(head_ != nullptr);
140
141 Entry* e = head_;
142 if (e->next_ == e) {
143 head_ = nullptr;
144 } else {
145 e->prev_->next_ = e->next_;
146 e->next_->prev_ = e->prev_;
147 head_ = e->next_;
148 }
149 if (clear != nullptr) {
150 clear(reinterpret_cast<void*>(e->t));
151 }
152 delete e;
153 }
154
155 void Remove(T item) {
156 if (head_ == nullptr) {
157 return;
158 } else if (head_ == head_->next_) {
159 if (head_->t == item) {
160 delete head_;
161 head_ = nullptr;
162 return;
163 }
164 } else {
165 Entry* current = head_;
166 do {
167 if (current->t == item) {
168 Entry* next = current->next_;
169 Entry* prev = current->prev_;
170 prev->next_ = next;
171 next->prev_ = prev;
172
173 if (current == head_) {
174 head_ = head_->next_;
175 }
176
177 delete current;
178 return;
179 }
180 current = current->next_;
181 } while (current != head_);
182 }
183 }
184
185 void RemoveAll(ClearFun clear = nullptr) {
186 while (HasHead()) {
187 RemoveHead(clear);
188 }
189 }
190
191 T head() const { return head_->t; }
192
193 bool HasHead() const { return head_ != nullptr; }
194
195 void Rotate() {
196 if (head_ != nullptr) {
197 ASSERT(head_->next_ != nullptr);
198 head_ = head_->next_;
199 }
200 }
201
202 private:
203 struct Entry {
204 explicit Entry(const T& t) : t(t), next_(nullptr), prev_(nullptr) {}
205 const T t;
206 Entry* next_;
207 Entry* prev_;
208 };
209
210 Entry* head_;
211
213};
214
216 public:
217 explicit DescriptorInfoBase(intptr_t fd) : fd_(fd) { ASSERT(fd_ != -1); }
218
220
221 // The OS descriptor.
222 intptr_t fd() { return fd_; }
223
224 // Whether this descriptor refers to an underlying listening OS socket.
225 virtual bool IsListeningSocket() const = 0;
226
227 // Inserts or updates a new Dart_Port which is interested in events specified
228 // in `mask`.
229 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) = 0;
230
231 // Removes a port from the interested listeners.
232 virtual void RemovePort(Dart_Port port) = 0;
233
234 // Removes all ports from the interested listeners.
235 virtual void RemoveAllPorts() = 0;
236
237 // Returns a port to which `events_ready` can be sent to. It will also
238 // decrease the token count by 1 for this port.
239 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) = 0;
240
241 // Will post `data` to all known Dart_Ports. It will also decrease the token
242 // count by 1 for all ports.
243 virtual void NotifyAllDartPorts(uintptr_t events) = 0;
244
245 // Returns `count` tokens for the given port.
246 virtual void ReturnTokens(Dart_Port port, int count) = 0;
247
248 // Returns the union of event masks of all ports. If a port has a non-positive
249 // token count it's mask is assumed to be 0.
250 virtual intptr_t Mask() = 0;
251
252 // Closes this descriptor.
253 virtual void Close() = 0;
254
255 protected:
256 intptr_t fd_;
257
258 private:
260};
261
262// Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on
263// windows) which is connected to a single Dart_Port.
264//
265// Subclasses of this class can be e.g. connected tcp sockets.
266template <typename DI>
267class DescriptorInfoSingleMixin : public DI {
268 private:
269 static constexpr int kTokenCount = 16;
270
271 public:
272 DescriptorInfoSingleMixin(intptr_t fd, bool disable_tokens)
273 : DI(fd),
274 port_(0),
275 tokens_(kTokenCount),
276 mask_(0),
277 disable_tokens_(disable_tokens) {}
278
280
281 virtual bool IsListeningSocket() const { return false; }
282
283 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) {
284 ASSERT(port_ == 0 || port == port_);
285 port_ = port;
286 mask_ = mask;
287 }
288
289 virtual void RemovePort(Dart_Port port) {
290 // TODO(dart:io): Find out where we call RemovePort() with the invalid
291 // port. Afterwards remove the part in the ASSERT here.
292 ASSERT(port_ == 0 || port_ == port);
293 port_ = 0;
294 mask_ = 0;
295 }
296
297 virtual void RemoveAllPorts() {
298 port_ = 0;
299 mask_ = 0;
300 }
301
302 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) {
303 ASSERT(IS_IO_EVENT(events_ready) ||
304 IS_EVENT(events_ready, kDestroyedEvent));
305 if (!disable_tokens_) {
306 tokens_--;
307 }
308 return port_;
309 }
310
311 virtual void NotifyAllDartPorts(uintptr_t events) {
312 // Unexpected close, asynchronous destroy or error events are the only
313 // ones we broadcast to all listeners.
314 ASSERT(IS_EVENT(events, kCloseEvent) || IS_EVENT(events, kErrorEvent) ||
315 IS_EVENT(events, kDestroyedEvent));
316
317 if (port_ != 0) {
318 DartUtils::PostInt32(port_, events);
319 }
320 if (!disable_tokens_) {
321 tokens_--;
322 }
323 }
324
325 virtual void ReturnTokens(Dart_Port port, int count) {
326 ASSERT(port_ == port);
327 if (!disable_tokens_) {
328 tokens_ += count;
329 }
330 ASSERT(tokens_ <= kTokenCount);
331 }
332
333 virtual intptr_t Mask() {
334 if (tokens_ <= 0) {
335 return 0;
336 }
337 return mask_;
338 }
339
340 virtual void Close() { DI::Close(); }
341
342 private:
343 Dart_Port port_;
344 int tokens_;
345 intptr_t mask_;
346 bool disable_tokens_;
347
349};
350
351// Describes a OS descriptor (e.g. file descriptor on linux or HANDLE on
352// windows) which is connected to multiple Dart_Port's.
353//
354// Subclasses of this class can be e.g. a listening socket which multiple
355// isolates are listening on.
356template <typename DI>
358 private:
359 static constexpr int kTokenCount = 4;
360
361 static bool SamePortValue(void* key1, void* key2) {
362 return reinterpret_cast<Dart_Port>(key1) ==
363 reinterpret_cast<Dart_Port>(key2);
364 }
365
366 static uint32_t GetHashmapHashFromPort(Dart_Port port) {
367 return static_cast<uint32_t>(port & 0xFFFFFFFF);
368 }
369
370 static void* GetHashmapKeyFromPort(Dart_Port port) {
371 return reinterpret_cast<void*>(port);
372 }
373
374 static bool IsReadingMask(intptr_t mask) {
375 if (mask == (1 << kInEvent)) {
376 return true;
377 } else {
378 ASSERT(mask == 0);
379 return false;
380 }
381 }
382
383 struct PortEntry {
384 Dart_Port dart_port;
385 intptr_t is_reading;
386 intptr_t token_count;
387
388 bool IsReady() { return token_count > 0 && is_reading != 0; }
389 };
390
391 public:
392 DescriptorInfoMultipleMixin(intptr_t fd, bool disable_tokens)
393 : DI(fd),
394 tokens_map_(&SamePortValue, kTokenCount),
395 disable_tokens_(disable_tokens) {}
396
398
399 virtual bool IsListeningSocket() const { return true; }
400
401 virtual void SetPortAndMask(Dart_Port port, intptr_t mask) {
402 SimpleHashMap::Entry* entry = tokens_map_.Lookup(
403 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), true);
404 PortEntry* pentry;
405 if (entry->value == nullptr) {
406 pentry = new PortEntry();
407 pentry->dart_port = port;
408 pentry->token_count = kTokenCount;
409 pentry->is_reading = IsReadingMask(mask);
410 entry->value = reinterpret_cast<void*>(pentry);
411
412 if (pentry->IsReady()) {
413 active_readers_.Add(pentry);
414 }
415 } else {
416 pentry = reinterpret_cast<PortEntry*>(entry->value);
417 bool was_ready = pentry->IsReady();
418 pentry->is_reading = IsReadingMask(mask);
419 bool is_ready = pentry->IsReady();
420
421 if (was_ready && !is_ready) {
422 active_readers_.Remove(pentry);
423 } else if (!was_ready && is_ready) {
424 active_readers_.Add(pentry);
425 }
426 }
427
428#ifdef DEBUG
429 // To ensure that all readers are ready.
430 int ready_count = 0;
431
432 if (active_readers_.HasHead()) {
433 PortEntry* root = reinterpret_cast<PortEntry*>(active_readers_.head());
434 PortEntry* current = root;
435 do {
436 ASSERT(current->IsReady());
437 ready_count++;
438 active_readers_.Rotate();
439 current = active_readers_.head();
440 } while (current != root);
441 }
442
443 for (SimpleHashMap::Entry* entry = tokens_map_.Start(); entry != nullptr;
444 entry = tokens_map_.Next(entry)) {
445 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
446 if (pentry->IsReady()) {
447 ready_count--;
448 }
449 }
450 // Ensure all ready items are in `active_readers_`.
451 ASSERT(ready_count == 0);
452#endif
453 }
454
455 virtual void RemovePort(Dart_Port port) {
456 SimpleHashMap::Entry* entry = tokens_map_.Lookup(
457 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false);
458 if (entry != nullptr) {
459 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
460 if (pentry->IsReady()) {
461 active_readers_.Remove(pentry);
462 }
463 tokens_map_.Remove(GetHashmapKeyFromPort(port),
464 GetHashmapHashFromPort(port));
465 delete pentry;
466 } else {
467 // NOTE: This is a listening socket which has been immediately closed.
468 //
469 // If a listening socket is not listened on, the event handler does not
470 // know about it beforehand. So the first time the event handler knows
471 // about it, is when it is supposed to be closed. We therefore do nothing
472 // here.
473 //
474 // But whether to close it, depends on whether other isolates have it open
475 // as well or not.
476 }
477 }
478
479 virtual void RemoveAllPorts() {
480 for (SimpleHashMap::Entry* entry = tokens_map_.Start(); entry != nullptr;
481 entry = tokens_map_.Next(entry)) {
482 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
483 entry->value = nullptr;
484 active_readers_.Remove(pentry);
485 delete pentry;
486 }
487 tokens_map_.Clear();
488 active_readers_.RemoveAll(DeletePortEntry);
489 }
490
491 virtual Dart_Port NextNotifyDartPort(intptr_t events_ready) {
492 // We're only sending `kInEvents` if there are multiple listeners (which is
493 // listening socktes).
494 ASSERT(IS_EVENT(events_ready, kInEvent) ||
495 IS_EVENT(events_ready, kDestroyedEvent));
496
497 if (active_readers_.HasHead()) {
498 PortEntry* pentry = reinterpret_cast<PortEntry*>(active_readers_.head());
499
500 // Update token count.
501 if (!disable_tokens_) {
502 pentry->token_count--;
503 }
504 if (pentry->token_count <= 0) {
505 active_readers_.RemoveHead();
506 } else {
507 active_readers_.Rotate();
508 }
509
510 return pentry->dart_port;
511 }
512 return 0;
513 }
514
515 virtual void NotifyAllDartPorts(uintptr_t events) {
516 // Unexpected close, asynchronous destroy or error events are the only
517 // ones we broadcast to all listeners.
518 ASSERT(IS_EVENT(events, kCloseEvent) || IS_EVENT(events, kErrorEvent) ||
519 IS_EVENT(events, kDestroyedEvent));
520
521 for (SimpleHashMap::Entry* entry = tokens_map_.Start(); entry != nullptr;
522 entry = tokens_map_.Next(entry)) {
523 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
524 DartUtils::PostInt32(pentry->dart_port, events);
525
526 // Update token count.
527 bool was_ready = pentry->IsReady();
528 if (!disable_tokens_) {
529 pentry->token_count--;
530 }
531
532 if (was_ready && (pentry->token_count <= 0)) {
533 active_readers_.Remove(pentry);
534 }
535 }
536 }
537
538 virtual void ReturnTokens(Dart_Port port, int count) {
539 SimpleHashMap::Entry* entry = tokens_map_.Lookup(
540 GetHashmapKeyFromPort(port), GetHashmapHashFromPort(port), false);
541 ASSERT(entry != nullptr);
542
543 PortEntry* pentry = reinterpret_cast<PortEntry*>(entry->value);
544 bool was_ready = pentry->IsReady();
545 if (!disable_tokens_) {
546 pentry->token_count += count;
547 }
548 ASSERT(pentry->token_count <= kTokenCount);
549 bool is_ready = pentry->IsReady();
550 if (!was_ready && is_ready) {
551 active_readers_.Add(pentry);
552 }
553 }
554
555 virtual intptr_t Mask() {
556 if (active_readers_.HasHead()) {
557 return 1 << kInEvent;
558 }
559 return 0;
560 }
561
562 virtual void Close() { DI::Close(); }
563
564 private:
565 static void DeletePortEntry(void* data) {
566 PortEntry* entry = reinterpret_cast<PortEntry*>(data);
567 delete entry;
568 }
569
570 // The [Dart_Port]s which are not paused (i.e. are interested in read events,
571 // i.e. `mask == (1 << kInEvent)`) and we have enough tokens to communicate
572 // with them.
573 CircularLinkedList<PortEntry*> active_readers_;
574
575 // A convenience mapping:
576 // Dart_Port -> struct PortEntry { dart_port, mask, token_count }
577 SimpleHashMap tokens_map_;
578
579 bool disable_tokens_;
580
581 DISALLOW_COPY_AND_ASSIGN(DescriptorInfoMultipleMixin);
582};
583
584} // namespace bin
585} // namespace dart
586
587// The event handler delegation class is OS specific.
588#if defined(DART_HOST_OS_FUCHSIA)
590#elif defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
592#elif defined(DART_HOST_OS_MACOS)
594#elif defined(DART_HOST_OS_WINDOWS)
595#include "bin/eventhandler_win.h"
596#else
597#error Unknown target os.
598#endif
599
600namespace dart {
601namespace bin {
602
604 public:
606 void SendData(intptr_t id, Dart_Port dart_port, int64_t data) {
607 delegate_.SendData(id, dart_port, data);
608 }
609
610 /**
611 * Signal to main thread that event handler is done.
612 */
613 void NotifyShutdownDone();
614
615 /**
616 * Start the event-handler.
617 */
618 static void Start();
619
620 /**
621 * Stop the event-handler. It's expected that there will be no further calls
622 * to SendData after a call to Stop.
623 */
624 static void Stop();
625
627
628 static void SendFromNative(intptr_t id, Dart_Port port, int64_t data);
629
630 private:
633
635};
636
637} // namespace bin
638} // namespace dart
639
640#endif // RUNTIME_BIN_EVENTHANDLER_H_
int count
static float next(float f)
static float prev(float f)
bool RemoveByValue(const V &value)
const Entry & Minimum() const
bool InsertOrChangePriority(const P &priority, const V &value)
void Clear(ClearFun clear=nullptr)
Definition hashmap.cc:111
Entry * Start() const
Definition hashmap.cc:123
Entry * Lookup(void *key, uint32_t hash, bool insert)
Definition hashmap.cc:20
void Remove(void *key, uint32_t hash)
Definition hashmap.cc:49
Entry * Next(Entry *p) const
Definition hashmap.cc:127
void RemoveAll(ClearFun clear=nullptr)
void(* ClearFun)(void *value)
void RemoveHead(ClearFun clear=nullptr)
static bool PostInt32(Dart_Port port_id, int32_t value)
Definition dartutils.cc:676
virtual void RemoveAllPorts()=0
virtual void RemovePort(Dart_Port port)=0
virtual void ReturnTokens(Dart_Port port, int count)=0
virtual void SetPortAndMask(Dart_Port port, intptr_t mask)=0
virtual void NotifyAllDartPorts(uintptr_t events)=0
virtual Dart_Port NextNotifyDartPort(intptr_t events_ready)=0
virtual intptr_t Mask()=0
virtual bool IsListeningSocket() const =0
virtual void SetPortAndMask(Dart_Port port, intptr_t mask)
DescriptorInfoMultipleMixin(intptr_t fd, bool disable_tokens)
virtual void RemovePort(Dart_Port port)
virtual void NotifyAllDartPorts(uintptr_t events)
virtual Dart_Port NextNotifyDartPort(intptr_t events_ready)
virtual void ReturnTokens(Dart_Port port, int count)
virtual bool IsListeningSocket() const
virtual Dart_Port NextNotifyDartPort(intptr_t events_ready)
virtual void ReturnTokens(Dart_Port port, int count)
virtual void SetPortAndMask(Dart_Port port, intptr_t mask)
DescriptorInfoSingleMixin(intptr_t fd, bool disable_tokens)
virtual void NotifyAllDartPorts(uintptr_t events)
virtual void RemovePort(Dart_Port port)
void SendData(intptr_t id, Dart_Port dart_port, int64_t data)
static EventHandlerImplementation * delegate()
static void SendFromNative(intptr_t id, Dart_Port port, int64_t data)
void SendData(intptr_t id, Dart_Port dart_port, int64_t data)
Dart_Port CurrentPort() const
void UpdateTimeout(Dart_Port port, int64_t timeout)
int64_t CurrentTimeout() const
int64_t Dart_Port
Definition dart_api.h:1524
MockDelegate delegate_
#define ASSERT(E)
#define IS_IO_EVENT(data)
#define IS_EVENT(data, event_bit)
uint8_t value
static constexpr intptr_t kTimerId
@ kShutdownWriteCommand
@ kReturnTokenCommand
@ kShutdownReadCommand
@ kSetEventMaskCommand
static constexpr intptr_t kShutdownId
static constexpr intptr_t kInfinityTimeout
static constexpr intptr_t kInterruptMessageSize
static int8_t data[kExtLength]
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define T