Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(419)

Side by Side Diff: dart/runtime/bin/eventhandler.h

Issue 905733002: Extract common Mask/Dart_Port settings of linux event handler implementation to eventhandler.h (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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_
OLDNEW
« no previous file with comments | « no previous file | dart/runtime/bin/eventhandler_android.h » ('j') | dart/runtime/bin/eventhandler_linux.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698