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

Side by Side Diff: runtime/observatory/lib/src/service/object.dart

Issue 1217823009: Make VM event streams look like real dart streams. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Polish Created 5 years, 5 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 part of service; 5 part of service;
6 6
7 /// An RpcException represents an exceptional event that happened 7 /// An RpcException represents an exceptional event that happened
8 /// while invoking an rpc. 8 /// while invoking an rpc.
9 abstract class RpcException implements Exception { 9 abstract class RpcException implements Exception {
10 RpcException(this.message); 10 RpcException(this.message);
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 419
420 String toString() { 420 String toString() {
421 if (endTokenPos == null) { 421 if (endTokenPos == null) {
422 return '${script.name}:token(${tokenPos})'; 422 return '${script.name}:token(${tokenPos})';
423 } else { 423 } else {
424 return '${script.name}:tokens(${tokenPos}-${endTokenPos})'; 424 return '${script.name}:tokens(${tokenPos}-${endTokenPos})';
425 } 425 }
426 } 426 }
427 } 427 }
428 428
429 class _EventStreamState {
430 VM _vm;
431 String streamId;
432
433 Function _onDone;
434
435 // A list of all subscribed controllers for this stream.
436 List _controllers = [];
437
438 // Completes when the listen rpc is finished.
439 Future _listenFuture;
440
441 // Completes when then cancel rpc is finished.
442 Future _cancelFuture;
443
444 _EventStreamState(this._vm, this.streamId, this._onDone);
445
446 Future _cancelController(StreamController controller) {
447 _controllers.remove(controller);
448 if (_controllers.isEmpty) {
449 assert(_listenFuture != null);
450 _listenFuture = null;
451 _cancelFuture = _vm._streamCancel(streamId);
452 _cancelFuture.then((_) {
453 if (_controllers.isEmpty) {
454 // No new listeners showed up during cancelation.
455 _onDone();
456 }
457 });
458 }
459 // No need to wait for _cancelFuture here.
460 return new Future.value(null);
461 }
462
463 Future<Stream> addStream() async {
464 var controller;
465 controller = new StreamController(
466 onCancel:() => _cancelController(controller));
467 _controllers.add(controller);
468 if (_cancelFuture != null) {
469 await _cancelFuture;
470 }
471 if (_listenFuture == null) {
472 _listenFuture = _vm._streamListen(streamId);
473 }
474 await _listenFuture;
475 return controller.stream;
476 }
477
478 void addEvent(ServiceEvent event) {
479 for (var controller in _controllers) {
480 controller.add(event);
481 }
482 }
483 }
484
429 /// State for a VM being inspected. 485 /// State for a VM being inspected.
430 abstract class VM extends ServiceObjectOwner { 486 abstract class VM extends ServiceObjectOwner {
431 @reflectable VM get vm => this; 487 @reflectable VM get vm => this;
432 @reflectable Isolate get isolate => null; 488 @reflectable Isolate get isolate => null;
433 489
434 // TODO(turnidge): The connection should not be stored in the VM object. 490 // TODO(turnidge): The connection should not be stored in the VM object.
435 bool get isDisconnected; 491 bool get isDisconnected;
436 492
437 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. 493 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache.
438 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 494 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
(...skipping 13 matching lines...) Expand all
452 @observable Duration get upTime => 508 @observable Duration get upTime =>
453 (new DateTime.now().difference(startTime)); 509 (new DateTime.now().difference(startTime));
454 510
455 VM() : super._empty(null) { 511 VM() : super._empty(null) {
456 name = 'vm'; 512 name = 'vm';
457 vmName = 'vm'; 513 vmName = 'vm';
458 _cache['vm'] = this; 514 _cache['vm'] = this;
459 update(toObservable({'id':'vm', 'type':'@VM'})); 515 update(toObservable({'id':'vm', 'type':'@VM'}));
460 } 516 }
461 517
462 final StreamController<ServiceEvent> events = 518 void postServiceEvent(String streamId, Map response, ByteData data) {
463 new StreamController.broadcast();
464
465 void postServiceEvent(Map response, ByteData data) {
466 var map = toObservable(response); 519 var map = toObservable(response);
467 assert(!map.containsKey('_data')); 520 assert(!map.containsKey('_data'));
468 if (data != null) { 521 if (data != null) {
469 map['_data'] = data; 522 map['_data'] = data;
470 } 523 }
471 if (map['type'] != 'Event') { 524 if (map['type'] != 'Event') {
472 Logger.root.severe( 525 Logger.root.severe(
473 "Expected 'Event' but found '${map['type']}'"); 526 "Expected 'Event' but found '${map['type']}'");
474 return; 527 return;
475 } 528 }
476 529
477 var eventIsolate = map['isolate']; 530 var eventIsolate = map['isolate'];
531 var event;
478 if (eventIsolate == null) { 532 if (eventIsolate == null) {
479 var event = new ServiceObject._fromMap(vm, map); 533 event = new ServiceObject._fromMap(vm, map);
480 events.add(event);
481 } else { 534 } else {
482 // getFromMap creates the Isolate if it hasn't been seen already. 535 // getFromMap creates the Isolate if it hasn't been seen already.
483 var isolate = getFromMap(map['isolate']); 536 var isolate = getFromMap(map['isolate']);
484 var event = new ServiceObject._fromMap(isolate, map); 537 event = new ServiceObject._fromMap(isolate, map);
485 if (event.kind == ServiceEvent.kIsolateExit) { 538 if (event.kind == ServiceEvent.kIsolateExit) {
486 _removeIsolate(isolate.id); 539 _removeIsolate(isolate.id);
487 } 540 }
488 isolate._onEvent(event); 541 }
489 events.add(event); 542 var eventStream = _eventStreams[streamId];
543 if (eventStream != null) {
544 eventStream.addEvent(event);
545 } else {
546 Logger.root.warning("Ignoring unexpected event on stream '${streamId}'");
490 } 547 }
491 } 548 }
492 549
493 void _removeIsolate(String isolateId) { 550 void _removeIsolate(String isolateId) {
494 assert(_isolateCache.containsKey(isolateId)); 551 assert(_isolateCache.containsKey(isolateId));
495 _isolateCache.remove(isolateId); 552 _isolateCache.remove(isolateId);
496 notifyPropertyChange(#isolates, true, false); 553 notifyPropertyChange(#isolates, true, false);
497 } 554 }
498 555
499 void _removeDeadIsolates(List newIsolates) { 556 void _removeDeadIsolates(List newIsolates) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 636 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
580 var obj = new ServiceObject._fromMap(this, response); 637 var obj = new ServiceObject._fromMap(this, response);
581 if ((obj != null) && obj.canCache) { 638 if ((obj != null) && obj.canCache) {
582 String objId = obj.id; 639 String objId = obj.id;
583 _cache.putIfAbsent(objId, () => obj); 640 _cache.putIfAbsent(objId, () => obj);
584 } 641 }
585 return obj; 642 return obj;
586 }); 643 });
587 } 644 }
588 645
646 void _dispatchEventToIsolate(ServiceEvent event) {
647 var isolate = event.isolate;
648 if (isolate != null) {
649 isolate._onEvent(event);
650 }
651 }
652
589 Future<ObservableMap> _fetchDirect() async { 653 Future<ObservableMap> _fetchDirect() async {
590 if (!loaded) { 654 if (!loaded) {
591 // TODO(turnidge): Instead of always listening to all streams, 655 // The vm service relies on these events to keep the VM and
592 // implement a stream abstraction in the service library so 656 // Isolate types up to date.
593 // that we only subscribe to the streams we want. 657 (await getIsolateEventStream()).listen(_dispatchEventToIsolate);
594 await _streamListen('Isolate'); 658 (await getDebugEventStream()).listen(_dispatchEventToIsolate);
595 await _streamListen('Debug'); 659 (await getEventStream('_Graph')).listen(_dispatchEventToIsolate);
596 await _streamListen('GC');
597 await _streamListen('_Echo');
598 await _streamListen('_Graph');
599 } 660 }
600 return await invokeRpcNoUpgrade('getVM', {}); 661 return await invokeRpcNoUpgrade('getVM', {});
601 } 662 }
602 663
603 Future<ServiceObject> getFlagList() { 664 Future<ServiceObject> getFlagList() {
604 return invokeRpc('getFlagList', {}); 665 return invokeRpc('getFlagList', {});
605 } 666 }
606 667
607 Future<ServiceObject> _streamListen(String streamId) { 668 Future<ServiceObject> _streamListen(String streamId) {
608 Map params = { 669 Map params = {
609 'streamId': streamId, 670 'streamId': streamId,
610 }; 671 };
611 return invokeRpc('streamListen', params); 672 return invokeRpc('streamListen', params);
612 } 673 }
613 674
675 Future<ServiceObject> _streamCancel(String streamId) {
676 Map params = {
677 'streamId': streamId,
678 };
679 return invokeRpc('streamCancel', params);
680 }
681
682 // A map from stream id to event stream state.
683 Map<String,_EventStreamState> _eventStreams = {};
684
685 /// Returns a single-subscription Stream object for a VM event stream.
686 Future<Stream> getEventStream(String streamId) async {
687 var eventStream = _eventStreams.putIfAbsent(
688 streamId, () => new _EventStreamState(
689 this, streamId, () => _eventStreams.remove(streamId)));
690 return eventStream.addStream();
691 }
692
693 Future<Stream> getIsolateEventStream() {
694 return getEventStream('Isolate');
695 }
696
697 Future<Stream> getDebugEventStream() {
698 return getEventStream('Debug');
699 }
700
701 Future<Stream> getGCEventStream() {
702 return getEventStream('GC');
703 }
704
614 /// Force the VM to disconnect. 705 /// Force the VM to disconnect.
615 void disconnect(); 706 void disconnect();
616 /// Completes when the VM first connects. 707 /// Completes when the VM first connects.
617 Future get onConnect; 708 Future get onConnect;
618 /// Completes when the VM disconnects or there was an error connecting. 709 /// Completes when the VM disconnects or there was an error connecting.
619 Future get onDisconnect; 710 Future get onDisconnect;
620 711
621 void _update(ObservableMap map, bool mapIsRef) { 712 void _update(ObservableMap map, bool mapIsRef) {
622 if (mapIsRef) { 713 if (mapIsRef) {
623 return; 714 return;
(...skipping 2829 matching lines...) Expand 10 before | Expand all | Expand 10 after
3453 var v = list[i]; 3544 var v = list[i];
3454 if ((v is ObservableMap) && _isServiceMap(v)) { 3545 if ((v is ObservableMap) && _isServiceMap(v)) {
3455 list[i] = owner.getFromMap(v); 3546 list[i] = owner.getFromMap(v);
3456 } else if (v is ObservableList) { 3547 } else if (v is ObservableList) {
3457 _upgradeObservableList(v, owner); 3548 _upgradeObservableList(v, owner);
3458 } else if (v is ObservableMap) { 3549 } else if (v is ObservableMap) {
3459 _upgradeObservableMap(v, owner); 3550 _upgradeObservableMap(v, owner);
3460 } 3551 }
3461 } 3552 }
3462 } 3553 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698