blob: 86bc832a01ba417cf512cfcc9472b5d77ff46315 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: implementation_imports
import 'dart:typed_data';
import 'package:fuchsia_inspect/src/vmo/vmo_holder.dart';
import 'package:zircon/zircon.dart';
/// A VmoHolder that simply wraps some ByteData.
class FakeVmoHolder implements VmoHolder {
/// The memory contents of this "VMO".
final ByteData bytes;
@override
Vmo get vmo => Vmo(null);
/// Size of the "VMO".
@override
final int size;
/// Creates a new [FakeVmoHolder] of the given size.
FakeVmoHolder(this.size) : bytes = Uint8List(size).buffer.asByteData();
/// Wraps a [FakeVmoHolder] around the given data.
FakeVmoHolder.usingData(this.bytes) : size = bytes.lengthInBytes;
/// Snapshots and loads a real VMO in this holder.
factory FakeVmoHolder.fromVmo(Vmo vmo, {int retries = 1024}) {
while (retries > 0) {
retries--;
// Spin until we find an even generation count (no concurrent update).
var headerData = vmo.read(16);
if (headerData.status != 0 ||
headerData.bytes.getInt64(8, Endian.little) % 2 != 0) {
continue;
}
// Read the entire VMO.
var sizeResult = vmo.getSize();
if (sizeResult.status != 0) {
continue;
}
var size = sizeResult.size;
var fullData = vmo.read(size);
if (fullData.status != 0) {
continue;
}
// Read the header again, and check that the generation counts match.
// This means we have a consistent snapshot.
var headerDataAfter = vmo.read(16);
if (headerDataAfter.status != 0 ||
headerData.bytes.getInt64(8, Endian.little) !=
headerDataAfter.bytes.getInt64(8, Endian.little)) {
continue;
}
return FakeVmoHolder.usingData(fullData.bytes);
}
throw AssertionError('Failed to load a real VMO in this holder');
}
@override
void beginWork() {}
@override
void commit() {}
/// Writes to the "VMO".
@override
void write(int offset, ByteData data) {
bytes.buffer.asUint8List().setAll(offset,
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
}
/// Reads from the "VMO".
@override
ByteData read(int offset, int size) {
var reading = ByteData(size);
reading.buffer
.asUint8List()
.setAll(0, bytes.buffer.asUint8List(offset, size));
return reading;
}
/// Writes int64 to VMO.
@override
void writeInt64(int offset, int value) =>
bytes.setInt64(offset, value, Endian.little);
/// Writes int64 directly to VMO for immediate visibility.
@override
void writeInt64Direct(int offset, int value) => writeInt64(offset, value);
/// Reads int64 from VMO.
@override
int readInt64(int offset) => bytes.getInt64(offset, Endian.little);
}