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

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: merge with master 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 /// Helper function for canceling a Future<StreamSubscription>.
8 Future cancelFutureSubscription(
9 Future<StreamSubscription> subscriptionFuture) async {
10 if (subscriptionFuture != null) {
11 var subscription = await subscriptionFuture;
12 return subscription.cancel();
13 } else {
14 return null;
15 }
16 }
17
7 /// An RpcException represents an exceptional event that happened 18 /// An RpcException represents an exceptional event that happened
8 /// while invoking an rpc. 19 /// while invoking an rpc.
9 abstract class RpcException implements Exception { 20 abstract class RpcException implements Exception {
10 RpcException(this.message); 21 RpcException(this.message);
11 22
12 String message; 23 String message;
13 } 24 }
14 25
15 /// A ServerRpcException represents an error returned by the VM. 26 /// A ServerRpcException represents an error returned by the VM.
16 class ServerRpcException extends RpcException { 27 class ServerRpcException extends RpcException {
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 430
420 String toString() { 431 String toString() {
421 if (endTokenPos == null) { 432 if (endTokenPos == null) {
422 return '${script.name}:token(${tokenPos})'; 433 return '${script.name}:token(${tokenPos})';
423 } else { 434 } else {
424 return '${script.name}:tokens(${tokenPos}-${endTokenPos})'; 435 return '${script.name}:tokens(${tokenPos}-${endTokenPos})';
425 } 436 }
426 } 437 }
427 } 438 }
428 439
440 class _EventStreamState {
441 VM _vm;
442 String streamId;
443
444 Function _onDone;
445
446 // A list of all subscribed controllers for this stream.
447 List _controllers = [];
448
449 // Completes when the listen rpc is finished.
450 Future _listenFuture;
451
452 // Completes when then cancel rpc is finished.
453 Future _cancelFuture;
454
455 _EventStreamState(this._vm, this.streamId, this._onDone);
456
457 Future _cancelController(StreamController controller) {
458 _controllers.remove(controller);
459 if (_controllers.isEmpty) {
460 assert(_listenFuture != null);
461 _listenFuture = null;
462 _cancelFuture = _vm._streamCancel(streamId);
463 _cancelFuture.then((_) {
464 if (_controllers.isEmpty) {
465 // No new listeners showed up during cancelation.
466 _onDone();
467 }
468 });
469 }
470 // No need to wait for _cancelFuture here.
471 return new Future.value(null);
472 }
473
474 Future<Stream> addStream() async {
475 var controller;
476 controller = new StreamController(
477 onCancel:() => _cancelController(controller));
478 _controllers.add(controller);
479 if (_cancelFuture != null) {
480 await _cancelFuture;
481 }
482 if (_listenFuture == null) {
483 _listenFuture = _vm._streamListen(streamId);
484 }
485 await _listenFuture;
486 return controller.stream;
487 }
488
489 void addEvent(ServiceEvent event) {
490 for (var controller in _controllers) {
491 controller.add(event);
492 }
493 }
494 }
495
429 /// State for a VM being inspected. 496 /// State for a VM being inspected.
430 abstract class VM extends ServiceObjectOwner { 497 abstract class VM extends ServiceObjectOwner {
431 @reflectable VM get vm => this; 498 @reflectable VM get vm => this;
432 @reflectable Isolate get isolate => null; 499 @reflectable Isolate get isolate => null;
433 500
434 // TODO(turnidge): The connection should not be stored in the VM object. 501 // TODO(turnidge): The connection should not be stored in the VM object.
435 bool get isDisconnected; 502 bool get isDisconnected;
436 503
437 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache. 504 // TODO(johnmccutchan): Ensure that isolates do not end up in _cache.
438 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>(); 505 Map<String,ServiceObject> _cache = new Map<String,ServiceObject>();
(...skipping 13 matching lines...) Expand all
452 @observable Duration get upTime => 519 @observable Duration get upTime =>
453 (new DateTime.now().difference(startTime)); 520 (new DateTime.now().difference(startTime));
454 521
455 VM() : super._empty(null) { 522 VM() : super._empty(null) {
456 name = 'vm'; 523 name = 'vm';
457 vmName = 'vm'; 524 vmName = 'vm';
458 _cache['vm'] = this; 525 _cache['vm'] = this;
459 update(toObservable({'id':'vm', 'type':'@VM'})); 526 update(toObservable({'id':'vm', 'type':'@VM'}));
460 } 527 }
461 528
462 final StreamController<ServiceEvent> events = 529 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); 530 var map = toObservable(response);
467 assert(!map.containsKey('_data')); 531 assert(!map.containsKey('_data'));
468 if (data != null) { 532 if (data != null) {
469 map['_data'] = data; 533 map['_data'] = data;
470 } 534 }
471 if (map['type'] != 'Event') { 535 if (map['type'] != 'Event') {
472 Logger.root.severe( 536 Logger.root.severe(
473 "Expected 'Event' but found '${map['type']}'"); 537 "Expected 'Event' but found '${map['type']}'");
474 return; 538 return;
475 } 539 }
476 540
477 var eventIsolate = map['isolate']; 541 var eventIsolate = map['isolate'];
542 var event;
478 if (eventIsolate == null) { 543 if (eventIsolate == null) {
479 var event = new ServiceObject._fromMap(vm, map); 544 event = new ServiceObject._fromMap(vm, map);
480 events.add(event);
481 } else { 545 } else {
482 // getFromMap creates the Isolate if it hasn't been seen already. 546 // getFromMap creates the Isolate if it hasn't been seen already.
483 var isolate = getFromMap(map['isolate']); 547 var isolate = getFromMap(map['isolate']);
484 var event = new ServiceObject._fromMap(isolate, map); 548 event = new ServiceObject._fromMap(isolate, map);
485 if (event.kind == ServiceEvent.kIsolateExit) { 549 if (event.kind == ServiceEvent.kIsolateExit) {
486 _removeIsolate(isolate.id); 550 _removeIsolate(isolate.id);
487 } 551 }
488 isolate._onEvent(event); 552 }
489 events.add(event); 553 var eventStream = _eventStreams[streamId];
554 if (eventStream != null) {
555 eventStream.addEvent(event);
556 } else {
557 Logger.root.warning("Ignoring unexpected event on stream '${streamId}'");
490 } 558 }
491 } 559 }
492 560
493 void _removeIsolate(String isolateId) { 561 void _removeIsolate(String isolateId) {
494 assert(_isolateCache.containsKey(isolateId)); 562 assert(_isolateCache.containsKey(isolateId));
495 _isolateCache.remove(isolateId); 563 _isolateCache.remove(isolateId);
496 notifyPropertyChange(#isolates, true, false); 564 notifyPropertyChange(#isolates, true, false);
497 } 565 }
498 566
499 void _removeDeadIsolates(List newIsolates) { 567 void _removeDeadIsolates(List newIsolates) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) { 647 return invokeRpcNoUpgrade(method, params).then((ObservableMap response) {
580 var obj = new ServiceObject._fromMap(this, response); 648 var obj = new ServiceObject._fromMap(this, response);
581 if ((obj != null) && obj.canCache) { 649 if ((obj != null) && obj.canCache) {
582 String objId = obj.id; 650 String objId = obj.id;
583 _cache.putIfAbsent(objId, () => obj); 651 _cache.putIfAbsent(objId, () => obj);
584 } 652 }
585 return obj; 653 return obj;
586 }); 654 });
587 } 655 }
588 656
657 void _dispatchEventToIsolate(ServiceEvent event) {
658 var isolate = event.isolate;
659 if (isolate != null) {
660 isolate._onEvent(event);
661 }
662 }
663
589 Future<ObservableMap> _fetchDirect() async { 664 Future<ObservableMap> _fetchDirect() async {
590 if (!loaded) { 665 if (!loaded) {
591 // TODO(turnidge): Instead of always listening to all streams, 666 // The vm service relies on these events to keep the VM and
592 // implement a stream abstraction in the service library so 667 // Isolate types up to date.
593 // that we only subscribe to the streams we want. 668 await listenEventStream(kIsolateStream, _dispatchEventToIsolate);
594 await _streamListen('Isolate'); 669 await listenEventStream(kDebugStream, _dispatchEventToIsolate);
595 await _streamListen('Debug'); 670 await listenEventStream(_kGraphStream, _dispatchEventToIsolate);
596 await _streamListen('GC');
597 await _streamListen('_Echo');
598 await _streamListen('_Graph');
599 } 671 }
600 return await invokeRpcNoUpgrade('getVM', {}); 672 return await invokeRpcNoUpgrade('getVM', {});
601 } 673 }
602 674
603 Future<ServiceObject> getFlagList() { 675 Future<ServiceObject> getFlagList() {
604 return invokeRpc('getFlagList', {}); 676 return invokeRpc('getFlagList', {});
605 } 677 }
606 678
607 Future<ServiceObject> _streamListen(String streamId) { 679 Future<ServiceObject> _streamListen(String streamId) {
608 Map params = { 680 Map params = {
609 'streamId': streamId, 681 'streamId': streamId,
610 }; 682 };
611 return invokeRpc('streamListen', params); 683 return invokeRpc('streamListen', params);
612 } 684 }
613 685
686 Future<ServiceObject> _streamCancel(String streamId) {
687 Map params = {
688 'streamId': streamId,
689 };
690 return invokeRpc('streamCancel', params);
691 }
692
693 // A map from stream id to event stream state.
694 Map<String,_EventStreamState> _eventStreams = {};
695
696 // Well-known stream ids.
697 static const kIsolateStream = 'Isolate';
698 static const kDebugStream = 'Debug';
699 static const kGCStream = 'GC';
700 static const _kGraphStream = '_Graph';
701
702 /// Returns a single-subscription Stream object for a VM event stream.
703 Future<Stream> getEventStream(String streamId) async {
704 var eventStream = _eventStreams.putIfAbsent(
705 streamId, () => new _EventStreamState(
706 this, streamId, () => _eventStreams.remove(streamId)));
707 return eventStream.addStream();
708 }
709
710 /// Helper function for listening to an event stream.
711 Future<StreamSubscription> listenEventStream(String streamId,
712 Function function) async {
713 var stream = await getEventStream(streamId);
714 return stream.listen(function);
715 }
716
614 /// Force the VM to disconnect. 717 /// Force the VM to disconnect.
615 void disconnect(); 718 void disconnect();
616 /// Completes when the VM first connects. 719 /// Completes when the VM first connects.
617 Future get onConnect; 720 Future get onConnect;
618 /// Completes when the VM disconnects or there was an error connecting. 721 /// Completes when the VM disconnects or there was an error connecting.
619 Future get onDisconnect; 722 Future get onDisconnect;
620 723
621 void _update(ObservableMap map, bool mapIsRef) { 724 void _update(ObservableMap map, bool mapIsRef) {
622 if (mapIsRef) { 725 if (mapIsRef) {
623 return; 726 return;
(...skipping 2829 matching lines...) Expand 10 before | Expand all | Expand 10 after
3453 var v = list[i]; 3556 var v = list[i];
3454 if ((v is ObservableMap) && _isServiceMap(v)) { 3557 if ((v is ObservableMap) && _isServiceMap(v)) {
3455 list[i] = owner.getFromMap(v); 3558 list[i] = owner.getFromMap(v);
3456 } else if (v is ObservableList) { 3559 } else if (v is ObservableList) {
3457 _upgradeObservableList(v, owner); 3560 _upgradeObservableList(v, owner);
3458 } else if (v is ObservableMap) { 3561 } else if (v is ObservableMap) {
3459 _upgradeObservableMap(v, owner); 3562 _upgradeObservableMap(v, owner);
3460 } 3563 }
3461 } 3564 }
3462 } 3565 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698