Add mount and unmount lifecycle callbacks to RPCDevices.

This commit is contained in:
Florian Nücke
2022-01-15 14:29:48 +01:00
parent 6a2f55e731
commit 1085a6b7a4
7 changed files with 279 additions and 5 deletions

View File

@@ -44,6 +44,24 @@ public interface RPCDevice extends Device {
*/
List<RPCMethod> getMethods();
/**
* Called to initialize this device.
* <p>
* This is called when the connected virtual machine starts, or when the device is added to an already running
* virtual machine.
*/
default void mount() {
}
/**
* Called to dispose this device.
* <p>
* Called when the connected virtual machine stops, or when the device is removed from a currently running
* virtual machine.
*/
default void unmount() {
}
/**
* Called when the device is suspended.
* <p>

View File

@@ -199,10 +199,7 @@ public final class ComputerBlockEntity extends ModBlockEntity implements Termina
public void setRemoved() {
super.setRemoved();
// super.remove() calls onUnload. This in turn only suspends, but we want to do
// a full clean-up when we get destroyed, so stuff inside us can delete out-of-nbt
// persisted runtime-only data such as ram.
virtualMachine.state.vmAdapter.unmount();
virtualMachine.stop();
}
@Override

View File

@@ -40,6 +40,8 @@ public final class RPCDeviceBusAdapter implements Steppable {
private final ArrayList<RPCDeviceWithIdentifier> devices = new ArrayList<>();
private final HashMap<UUID, RPCDeviceList> devicesById = new HashMap<>();
private final Set<RPCDevice> unmountedDevices = new HashSet<>();
private final Set<RPCDevice> mountedDevices = new HashSet<>();
private final Lock pauseLock = new ReentrantLock();
private boolean isPaused;
@@ -69,6 +71,22 @@ public final class RPCDeviceBusAdapter implements Steppable {
///////////////////////////////////////////////////////////////////
public void mount() {
for (final RPCDevice device : unmountedDevices) {
device.mount();
}
mountedDevices.addAll(unmountedDevices);
unmountedDevices.clear();
}
public void unmount() {
for (final RPCDevice device : mountedDevices) {
device.unmount();
}
unmountedDevices.addAll(mountedDevices);
mountedDevices.clear();
}
public void suspend() {
for (final RPCDeviceWithIdentifier info : devices) {
info.device.suspend();
@@ -100,6 +118,7 @@ public final class RPCDeviceBusAdapter implements Steppable {
devices.clear();
devicesById.clear();
unmountedDevices.clear();
// How device grouping works:
// Each device can have multiple UUIDs due to being attached to multiple bus elements.
@@ -144,11 +163,31 @@ public final class RPCDeviceBusAdapter implements Steppable {
.add(identifier);
});
final Set<RPCDevice> newDevices = new HashSet<>();
identifiersByDevice.forEach((device, identifiers) -> {
final UUID identifier = selectIdentifierDeterministically(identifiers);
devices.add(new RPCDeviceWithIdentifier(identifier, device));
devicesById.put(identifier, device);
newDevices.add(device);
});
// Add new devices to list of unmounted devices. List was cleared, so removed devices previously in
// list of unmounted devices are already gone.
for (final RPCDevice newDevice : newDevices) {
if (!mountedDevices.contains(newDevice)) {
unmountedDevices.add(newDevice);
}
}
// Remove removed devices from list of mounted devices.
final Iterator<RPCDevice> mountedDeviceIterator = mountedDevices.iterator();
while (mountedDeviceIterator.hasNext()) {
final RPCDevice device = mountedDeviceIterator.next();
if (!newDevices.contains(device)) {
device.unmount();
mountedDeviceIterator.remove();
}
}
}
public void tick() {

View File

@@ -35,6 +35,20 @@ public final class RPCDeviceList implements RPCDevice {
.collect(Collectors.toList());
}
@Override
public void mount() {
for (final RPCDevice device : devices) {
device.mount();
}
}
@Override
public void unmount() {
for (final RPCDevice device : devices) {
device.unmount();
}
}
@Override
public void suspend() {
for (final RPCDevice device : devices) {

View File

@@ -348,7 +348,7 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R
virtualMachine.suspend();
// Full unload to release out-of-nbt persisted runtime-only data such as ram.
virtualMachine.state.vmAdapter.unmount();
virtualMachine.stop();
}
@Override

View File

@@ -198,6 +198,7 @@ public abstract class AbstractVirtualMachine implements VirtualMachine {
state.board.reset();
state.rpcAdapter.reset();
state.rpcAdapter.unmount();
state.vmAdapter.unmount();
runner = null;
@@ -337,6 +338,8 @@ public abstract class AbstractVirtualMachine implements VirtualMachine {
runner = createRunner();
}
state.rpcAdapter.mount();
setRunState(VMRunState.RUNNING);
// Only start running next tick. This gives loaded devices one tick to do async