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

Unified Diff: runtime/observatory/lib/src/elements/debugger.dart

Issue 1007863003: Allow Observatory debugger to switch isolates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: runtime/observatory/lib/src/elements/debugger.dart
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 4a9bdf83bf0bc91a33c30a04c1519c21cd68b4ea..0bd8e019dac1d422fce3f0000212fb7fbc5fbc7b 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -30,9 +30,9 @@ class HelpCommand extends DebuggerCommand {
String _nameAndAlias(Command cmd) {
if (cmd.alias == null) {
- return cmd.name;
+ return cmd.fullName;
} else {
- return '${cmd.name}, ${cmd.alias}';
+ return '${cmd.fullName}, ${cmd.alias}';
}
}
@@ -51,7 +51,7 @@ class HelpCommand extends DebuggerCommand {
"\nFor more information on a specific command type 'help <command>'\n"
"\n"
"Command prefixes are accepted (e.g. 'h' for 'help')\n"
- "Hit [TAB] to complete a command (try 'i[TAB][TAB]')\n"
+ "Hit [TAB] to complete a command (try 'is[TAB][TAB]')\n"
"Hit [ENTER] to repeat the last command\n"
"Use up/down arrow for command history\n");
return new Future.value(null);
@@ -409,7 +409,7 @@ class BreakCommand extends DebuggerCommand {
Future<List<String>> complete(List<String> args) {
if (args.length != 1) {
- return new Future.value([]);
+ return new Future.value([args.join('')]);
}
// TODO - fix SourceLocation complete
return new Future.value(SourceLocation.complete(debugger, args[0]));
@@ -493,7 +493,7 @@ class ClearCommand extends DebuggerCommand {
Future<List<String>> complete(List<String> args) {
if (args.length != 1) {
- return new Future.value([]);
+ return new Future.value([args.join('')]);
}
return new Future.value(SourceLocation.complete(debugger, args[0]));
}
@@ -603,14 +603,116 @@ class InfoBreakpointsCommand extends DebuggerCommand {
'Syntax: info breakpoints\n';
}
-class InfoIsolatesCommand extends DebuggerCommand {
- InfoIsolatesCommand(Debugger debugger) : super(debugger, 'isolates', []);
+class InfoFrameCommand extends DebuggerCommand {
+ InfoFrameCommand(Debugger debugger) : super(debugger, 'frame', []);
+
+ Future run(List<String> args) {
+ if (args.length > 0) {
+ debugger.console.print('info frame expects no arguments');
+ return new Future.value(null);
+ }
+ debugger.console.print('frame = ${debugger.currentFrame}');
+ return new Future.value(null);
+ }
+
+ String helpShort = 'Show current frame';
+
+ String helpLong =
+ 'Show current frame.\n'
+ '\n'
+ 'Syntax: info frame\n';
+}
+
+class IsolateCommand extends DebuggerCommand {
+ IsolateCommand(Debugger debugger) : super(debugger, 'isolate', [
+ new IsolateListCommand(debugger),
+ new IsolateNameCommand(debugger),
+ ]) {
+ alias = 'i';
+ }
+
+ Future run(List<String> args) {
+ if (args.length != 1) {
+ debugger.console.print('isolate expects one argument');
+ return new Future.value(null);
+ }
+ var arg = args[0].trim();
+ var num = int.parse(arg, onError:(_) => null);
+
+ var candidate;
+ for (var isolate in debugger.vm.isolates) {
+ if (num != null && num == isolate.number) {
+ candidate = isolate;
+ break;
+ } else if (arg == isolate.name) {
+ if (candidate != null) {
+ debugger.console.print(
+ "Isolate identifier '${arg}' is ambiguous: "
+ 'use the isolate number instead');
+ return new Future.value(null);
+ }
+ candidate = isolate;
+ }
+ }
+ if (candidate == null) {
+ debugger.console.print("Invalid isolate identifier '${arg}'");
+ } else {
+ if (candidate == debugger.isolate) {
+ debugger.console.print(
+ "Current isolate is already ${candidate.number} '${candidate.name}'");
+ } else {
+ debugger.console.print(
+ "Switching to isolate ${candidate.number} '${candidate.name}'");
+ debugger.isolate = candidate;
+ }
+ }
+ return new Future.value(null);
+ }
+
+ Future<List<String>> complete(List<String> args) {
+ if (args.length != 1) {
+ return new Future.value([args.join('')]);
+ }
+ var isolates = debugger.vm.isolates.toList();
+ isolates.sort((a, b) => a.startTime.compareTo(b.startTime));
+ var result = [];
+ for (var isolate in isolates) {
+ var str = isolate.number.toString();
+ if (str.startsWith(args[0])) {
+ result.add('$str ');
+ }
+ }
+ for (var isolate in isolates) {
+ if (isolate.name.startsWith(args[0])) {
+ result.add('${isolate.name} ');
+ }
+ }
+ return new Future.value(result);
+ }
+ String helpShort = 'Switch the current isolate';
+
+ String helpLong =
+ 'Switch the current isolate.\n'
+ '\n'
+ 'Syntax: isolate <number>\n'
+ ' isolate <name>\n';
+}
+
+class IsolateListCommand extends DebuggerCommand {
+ IsolateListCommand(Debugger debugger) : super(debugger, 'list', []);
Future run(List<String> args) {
- for (var isolate in debugger.isolate.vm.isolates) {
+ if (debugger.vm == null) {
+ debugger.console.print(
+ "Internal error: vm has not been set");
+ return new Future.value(null);
+ }
+ var isolates = debugger.vm.isolates.toList();
+ isolates.sort((a, b) => a.startTime.compareTo(b.startTime));
+ for (var isolate in isolates) {
String current = (isolate == debugger.isolate ? ' *' : '');
debugger.console.print(
- "Isolate ${isolate.id} '${isolate.name}'${current}");
+ "Isolate ${isolate.number} '${isolate.name}'${current}");
}
return new Future.value(null);
}
@@ -620,35 +722,32 @@ class InfoIsolatesCommand extends DebuggerCommand {
String helpLong =
'List all isolates.\n'
'\n'
- 'Syntax: info isolates\n';
+ 'Syntax: isolate list\n';
}
-class InfoFrameCommand extends DebuggerCommand {
- InfoFrameCommand(Debugger debugger) : super(debugger, 'frame', []);
+class IsolateNameCommand extends DebuggerCommand {
+ IsolateNameCommand(Debugger debugger) : super(debugger, 'name', []);
Future run(List<String> args) {
- if (args.length > 0) {
- debugger.console.print('info frame expects 1 argument');
+ if (args.length != 1) {
+ debugger.console.print('isolate name expects one argument');
return new Future.value(null);
}
- debugger.console.print('frame = ${debugger.currentFrame}');
- return new Future.value(null);
+ return debugger.isolate.setName(args[0]);
}
- String helpShort = 'Show current frame';
+ String helpShort = 'Rename an isolate';
String helpLong =
- 'Show current frame.\n'
+ 'Rename an isolate.\n'
'\n'
- 'Syntax: info frame\n';
+ 'Syntax: isolate name <name>\n';
}
class InfoCommand extends DebuggerCommand {
InfoCommand(Debugger debugger) : super(debugger, 'info', [
new InfoBreakpointsCommand(debugger),
- new InfoIsolatesCommand(debugger),
- new InfoFrameCommand(debugger),
- ]);
+ new InfoFrameCommand(debugger)]);
Future run(List<String> args) {
debugger.console.print("'info' expects a subcommand (see 'help info')");
@@ -724,6 +823,7 @@ class RefreshCommand extends DebuggerCommand {
// Tracks the state for an isolate debugging session.
class ObservatoryDebugger extends Debugger {
RootCommand cmd;
+ DebuggerPageElement page;
DebuggerConsoleElement console;
DebuggerStackElement stackElement;
ServiceMap stack;
@@ -758,14 +858,17 @@ class ObservatoryDebugger extends Debugger {
new ClearCommand(this),
new DeleteCommand(this),
new InfoCommand(this),
+ new IsolateCommand(this),
new RefreshCommand(this),
]);
}
- void set isolate(Isolate iso) {
+ VM get vm => page.app.vm;
+
+ void updateIsolate(Isolate iso) {
_isolate = iso;
if (_isolate != null) {
- _isolate.reload().then((_) {
+ _isolate.reload().then((response) {
// TODO(turnidge): Currently the debugger relies on all libs
// being loaded. Fix this.
var pending = [];
@@ -775,26 +878,46 @@ class ObservatoryDebugger extends Debugger {
}
}
Future.wait(pending).then((_) {
- _isolate.vm.events.stream.listen(_onEvent);
+ if (_subscription == null) {
+ _subscription = vm.events.stream.listen(_onEvent);
+ }
_refreshStack(isolate.pauseEvent).then((_) {
reportStatus();
});
});
});
+ } else {
+ reportStatus();
}
}
+
+ void set isolate(Isolate iso) {
+ // Setting the page's isolate will trigger updateIsolate to be called.
+ //
+ // TODO(turnidge): Rework ownership of the ObservatoryDebugger in another
+ // change.
+ page.isolate = iso;
+ }
Isolate get isolate => _isolate;
Isolate _isolate;
+ var _subscription;
void init() {
console.newline();
console.printBold("Type 'h' for help");
+ // Wait a bit and if polymer still hasn't set up the isolate,
+ // report this to the user.
+ new Timer(const Duration(seconds:1), () {
+ if (isolate == null) {
+ reportStatus();
+ }
+ });
}
Future refreshStack() {
return _refreshStack(isolate.pauseEvent).then((_) {
- reportStatus();
- });
+ reportStatus();
+ });
}
bool isolatePaused() {
@@ -830,7 +953,9 @@ class ObservatoryDebugger extends Debugger {
}
void reportStatus() {
- if (_isolate.idle) {
+ if (_isolate == null) {
+ console.print('No current isolate');
+ } else if (_isolate.idle) {
console.print('Isolate is idle');
} else if (_isolate.running) {
console.print("Isolate is running (type 'pause' to interrupt)");
@@ -902,13 +1027,28 @@ class ObservatoryDebugger extends Debugger {
}
void _onEvent(ServiceEvent event) {
- if (event.owner != isolate) {
- return;
- }
switch(event.eventType) {
- case ServiceEvent.kIsolateExit:
- console.print('Isolate shutdown');
- isolate = null;
+ case ServiceEvent.kIsolateStart: {
+ var iso = event.owner;
+ console.print(
+ "Isolate ${iso.number} '${iso.name}' has been created");
+ break;
+ }
+
+ case ServiceEvent.kIsolateExit: {
+ var iso = event.owner;
+ if (iso == isolate) {
+ console.print("The current isolate has exited");
+ } else {
+ console.print(
+ "Isolate ${iso.number} '${iso.name}' has exited");
+ }
+ break;
+ }
+
+ case ServiceEvent.kIsolateUpdate:
+ var iso = event.owner;
+ console.print("Isolate ${iso.number} renamed to '${iso.name}'");
break;
case ServiceEvent.kPauseStart:
@@ -916,25 +1056,30 @@ class ObservatoryDebugger extends Debugger {
case ServiceEvent.kPauseBreakpoint:
case ServiceEvent.kPauseInterrupted:
case ServiceEvent.kPauseException:
- _refreshStack(event).then((_) {
- _reportPause(event);
- });
+ if (event.owner == isolate) {
+ _refreshStack(event).then((_) {
+ _reportPause(event);
+ });
+ }
break;
case ServiceEvent.kResume:
- console.print('Continuing...');
+ if (event.owner == isolate) {
+ console.print('Continuing...');
+ }
break;
case ServiceEvent.kBreakpointAdded:
case ServiceEvent.kBreakpointResolved:
case ServiceEvent.kBreakpointRemoved:
- _reportBreakpointEvent(event);
+ if (event.owner == isolate) {
+ _reportBreakpointEvent(event);
+ }
break;
case ServiceEvent.kIsolateStart:
case ServiceEvent.kGraph:
case ServiceEvent.kGC:
- // Ignore these events for now.
break;
default:
@@ -1008,16 +1153,19 @@ class ObservatoryDebugger extends Debugger {
@CustomTag('debugger-page')
class DebuggerPageElement extends ObservatoryElement {
+ @published ObservatoryApplication app;
@published Isolate isolate;
isolateChanged(oldValue) {
if (isolate != null) {
- debugger.isolate = isolate;
+ debugger.updateIsolate(isolate);
}
}
ObservatoryDebugger debugger = new ObservatoryDebugger();
- DebuggerPageElement.created() : super.created();
+ DebuggerPageElement.created() : super.created() {
+ debugger.page = this;
+ }
@override
void attached() {
« no previous file with comments | « runtime/observatory/lib/src/debugger/debugger.dart ('k') | runtime/observatory/lib/src/elements/isolate_summary.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698