34fb48bb8a
Migrates libraries dependent only on already migrated libraries. Change-Id: I0e85ee8dbc2afce031b92e0009e71c206a55af28 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/179502 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Jens Johansen <jensj@google.com>
218 lines
6.0 KiB
Dart
218 lines
6.0 KiB
Dart
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// @dart = 2.9
|
|
|
|
import "dart:convert";
|
|
import "dart:io";
|
|
|
|
import "package:vm_service/vm_service.dart" as vmService;
|
|
import "package:vm_service/vm_service_io.dart" as vmService;
|
|
|
|
export "package:vm_service/vm_service.dart";
|
|
export "package:vm_service/vm_service_io.dart";
|
|
|
|
class VMServiceHelper {
|
|
vmService.VmService _serviceClient;
|
|
vmService.VmService get serviceClient => _serviceClient;
|
|
|
|
VMServiceHelper();
|
|
|
|
Future connect(Uri observatoryUri) async {
|
|
String path = observatoryUri.path;
|
|
if (!path.endsWith("/")) path += "/";
|
|
String wsUriString = 'ws://${observatoryUri.authority}${path}ws';
|
|
_serviceClient = await vmService.vmServiceConnectUri(wsUriString,
|
|
log: const StdOutLog());
|
|
}
|
|
|
|
Future disconnect() async {
|
|
await _serviceClient.dispose();
|
|
}
|
|
|
|
Future<bool> waitUntilPaused(String isolateId) async {
|
|
int nulls = 0;
|
|
while (true) {
|
|
bool result = await isPaused(isolateId);
|
|
if (result == null) {
|
|
nulls++;
|
|
if (nulls > 5) {
|
|
// We've now asked for the isolate 5 times and in all cases gotten
|
|
// `Sentinel`. Most likely things aren't working for whatever reason.
|
|
return false;
|
|
}
|
|
} else if (result) {
|
|
return true;
|
|
} else {
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<bool> isPaused(String isolateId) async {
|
|
dynamic tmp = await _serviceClient.getIsolate(isolateId);
|
|
if (tmp is vmService.Isolate) {
|
|
vmService.Isolate isolate = tmp;
|
|
if (isolate.pauseEvent.kind != "Resume") return true;
|
|
return false;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<bool> isPausedAtStart(String isolateId) async {
|
|
dynamic tmp = await _serviceClient.getIsolate(isolateId);
|
|
if (tmp is vmService.Isolate) {
|
|
vmService.Isolate isolate = tmp;
|
|
return isolate.pauseEvent.kind == "PauseStart";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Future<bool> isPausedAtExit(String isolateId) async {
|
|
dynamic tmp = await _serviceClient.getIsolate(isolateId);
|
|
if (tmp is vmService.Isolate) {
|
|
vmService.Isolate isolate = tmp;
|
|
return isolate.pauseEvent.kind == "PauseExit";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Future<vmService.AllocationProfile> forceGC(String isolateId) async {
|
|
await waitUntilIsolateIsRunnable(isolateId);
|
|
int expectGcAfter = new DateTime.now().millisecondsSinceEpoch;
|
|
while (true) {
|
|
vmService.AllocationProfile allocationProfile;
|
|
try {
|
|
allocationProfile =
|
|
await _serviceClient.getAllocationProfile(isolateId, gc: true);
|
|
} catch (e) {
|
|
print(e.runtimeType);
|
|
rethrow;
|
|
}
|
|
if (allocationProfile.dateLastServiceGC != null &&
|
|
allocationProfile.dateLastServiceGC >= expectGcAfter) {
|
|
return allocationProfile;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<bool> isIsolateRunnable(String isolateId) async {
|
|
dynamic tmp = await _serviceClient.getIsolate(isolateId);
|
|
if (tmp is vmService.Isolate) {
|
|
vmService.Isolate isolate = tmp;
|
|
return isolate.runnable;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
Future<void> waitUntilIsolateIsRunnable(String isolateId) async {
|
|
int nulls = 0;
|
|
while (true) {
|
|
bool result = await isIsolateRunnable(isolateId);
|
|
if (result == null) {
|
|
nulls++;
|
|
if (nulls > 5) {
|
|
// We've now asked for the isolate 5 times and in all cases gotten
|
|
// `Sentinel`. Most likely things aren't working for whatever reason.
|
|
return;
|
|
}
|
|
} else if (result) {
|
|
return;
|
|
} else {
|
|
await Future.delayed(const Duration(milliseconds: 100));
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<String> getIsolateId() async {
|
|
vmService.VM vm = await _serviceClient.getVM();
|
|
if (vm.isolates.length != 1) {
|
|
throw "Expected 1 isolate, got ${vm.isolates.length}";
|
|
}
|
|
vmService.IsolateRef isolateRef = vm.isolates.single;
|
|
return isolateRef.id;
|
|
}
|
|
}
|
|
|
|
class StdOutLog implements vmService.Log {
|
|
const StdOutLog();
|
|
|
|
@override
|
|
void severe(String message) {
|
|
print("> SEVERE: $message");
|
|
}
|
|
|
|
@override
|
|
void warning(String message) {
|
|
print("> WARNING: $message");
|
|
}
|
|
}
|
|
|
|
abstract class LaunchingVMServiceHelper extends VMServiceHelper {
|
|
Process _process;
|
|
Process get process => _process;
|
|
|
|
bool _started = false;
|
|
|
|
void start(List<String> scriptAndArgs,
|
|
{void stdinReceiver(String line),
|
|
void stderrReceiver(String line)}) async {
|
|
if (_started) throw "Already started";
|
|
_started = true;
|
|
_process = await Process.start(
|
|
Platform.resolvedExecutable,
|
|
["--pause_isolates_on_start", "--enable-vm-service=0"]
|
|
..addAll(scriptAndArgs));
|
|
_process.stdout
|
|
.transform(utf8.decoder)
|
|
.transform(new LineSplitter())
|
|
.listen((line) {
|
|
const kObservatoryListening = 'Observatory listening on ';
|
|
if (line.startsWith(kObservatoryListening)) {
|
|
Uri observatoryUri =
|
|
Uri.parse(line.substring(kObservatoryListening.length));
|
|
_setupAndRun(observatoryUri).catchError((e, st) {
|
|
// Manually kill the process or it will leak,
|
|
// see http://dartbug.com/42918
|
|
killProcess();
|
|
// This seems to rethrow.
|
|
throw e;
|
|
});
|
|
}
|
|
if (stdinReceiver != null) {
|
|
stdinReceiver(line);
|
|
} else {
|
|
stdout.writeln("> $line");
|
|
}
|
|
});
|
|
_process.stderr
|
|
.transform(utf8.decoder)
|
|
.transform(new LineSplitter())
|
|
.listen((line) {
|
|
if (stderrReceiver != null) {
|
|
stderrReceiver(line);
|
|
} else {
|
|
stderr.writeln("> $line");
|
|
}
|
|
});
|
|
// ignore: unawaited_futures
|
|
_process.exitCode.then((value) {
|
|
processExited(value);
|
|
});
|
|
}
|
|
|
|
void processExited(int exitCode) {}
|
|
|
|
void killProcess() {
|
|
_process.kill();
|
|
}
|
|
|
|
Future _setupAndRun(Uri observatoryUri) async {
|
|
await connect(observatoryUri);
|
|
await run();
|
|
}
|
|
|
|
Future<void> run();
|
|
}
|