From ef895a4bf9ed07a8ea6689a98d5f755180b6df50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 8 Jan 2021 20:02:05 +0100 Subject: [PATCH] Make VM lifecycle events allow being used to sync up device state pre/post resume. --- .../device/vm/VMDeviceLifecycleEventType.java | 36 +++++++++++++++---- .../item/ByteBufferFlashMemoryVMDevice.java | 2 +- .../item/FirmwareFlashMemoryVMDevice.java | 2 +- .../common/tileentity/ComputerTileEntity.java | 14 ++++---- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/main/java/li/cil/oc2/api/bus/device/vm/VMDeviceLifecycleEventType.java b/src/main/java/li/cil/oc2/api/bus/device/vm/VMDeviceLifecycleEventType.java index 08c9188a..2b57d6be 100644 --- a/src/main/java/li/cil/oc2/api/bus/device/vm/VMDeviceLifecycleEventType.java +++ b/src/main/java/li/cil/oc2/api/bus/device/vm/VMDeviceLifecycleEventType.java @@ -1,6 +1,29 @@ package li.cil.oc2.api.bus.device.vm; public enum VMDeviceLifecycleEventType { + /** + * Fired exactly once, when the VM first starts running. + *

+ * Fired after all devices reported success from {@link VMDevice#load(VMContext)}. + *

+ * If a running VM is restored from a saved state, this event will not be fired. It is + * intended for initializing the VM state on boot, e.g. by loading initial executable + * code into memory. + *

+ * This is invoked from the worker thread running the VM. + */ + INITIALIZING, + + /** + * Fired when the VM is paused, typically before state is persisted. + *

+ * Allows devices that offer interaction to external code-flow to suspend + * such interactions until {@link #RESUMED_RUNNING} is fired. This is required + * if such interactions may modify VM state, to prevent corrupting data being + * serialized asynchronously. + */ + PAUSING, + /** * Fired when the VM resumes running. *

@@ -13,17 +36,16 @@ public enum VMDeviceLifecycleEventType { RESUME_RUNNING, /** - * Fired exactly once, when the VM first starts running. + * Fired when the VM resumed running. *

- * Fired after all devices reported success from {@link VMDevice#load(VMContext)}. + * Fired after {@link #RESUME_RUNNING} has been fired and handled by all devices. *

- * If a running VM is restored from a saved state, this event will not be fired. It is - * intended for initializing the VM state on boot, e.g. by loading initial executable - * code into memory. + * Allows device initialization that relies on all other devices having fully loaded. *

- * This is invoked from the worker thread running the VM. + * Typically this is used in combination with {@link #PAUSING}, to re-enable external + * interactions after VM state is guaranteed to be safe to modify again. */ - INITIALIZE, + RESUMED_RUNNING, /** * Fired when the device is disposed, either because the VM is disposed or the source diff --git a/src/main/java/li/cil/oc2/common/bus/device/item/ByteBufferFlashMemoryVMDevice.java b/src/main/java/li/cil/oc2/common/bus/device/item/ByteBufferFlashMemoryVMDevice.java index 4748c176..5c19d966 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/item/ByteBufferFlashMemoryVMDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/item/ByteBufferFlashMemoryVMDevice.java @@ -64,7 +64,7 @@ public final class ByteBufferFlashMemoryVMDevice extends IdentityProxy @Override public void handleLifecycleEvent(final VMDeviceLifecycleEventType event) { switch (event) { - case INITIALIZE: + case INITIALIZING: // TODO Have start address passed with event? firmware.run(memoryMap, 0x80000000L); break; diff --git a/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java b/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java index 86449ca0..b2442403 100644 --- a/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java +++ b/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java @@ -407,18 +407,19 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic joinVirtualMachine(); - tag.put(TERMINAL_TAG_NAME, NBTSerialization.serialize(terminal)); - - tag.put(BUS_ELEMENT_TAG_NAME, NBTSerialization.serialize(busElement)); - tag.put(VIRTUAL_MACHINE_TAG_NAME, NBTSerialization.serialize(virtualMachine)); - if (runner != null) { tag.put(RUNNER_TAG_NAME, NBTSerialization.serialize(runner)); + virtualMachine.vmAdapter.fireLifecycleEvent(VMDeviceLifecycleEventType.PAUSING); runner.scheduleResumeEvent(); // Allow synchronizing to async device saves. } else { NBTUtils.putEnum(tag, RUN_STATE_TAG_NAME, runState); } + tag.put(TERMINAL_TAG_NAME, NBTSerialization.serialize(terminal)); + + tag.put(BUS_ELEMENT_TAG_NAME, NBTSerialization.serialize(busElement)); + tag.put(VIRTUAL_MACHINE_TAG_NAME, NBTSerialization.serialize(virtualMachine)); + final CompoundNBT items = new CompoundNBT(); items.put(MEMORY_TAG_NAME, memoryItemHandler.serializeNBT()); items.put(HARD_DRIVE_TAG_NAME, hardDriveItemHandler.serializeNBT()); @@ -739,12 +740,13 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic protected void handleBeforeRun() { if (!firedInitializationEvent) { firedInitializationEvent = true; - virtualMachine.vmAdapter.fireLifecycleEvent(VMDeviceLifecycleEventType.INITIALIZE); + virtualMachine.vmAdapter.fireLifecycleEvent(VMDeviceLifecycleEventType.INITIALIZING); } if (!firedResumeEvent) { firedResumeEvent = true; virtualMachine.vmAdapter.fireLifecycleEvent(VMDeviceLifecycleEventType.RESUME_RUNNING); + virtualMachine.vmAdapter.fireLifecycleEvent(VMDeviceLifecycleEventType.RESUMED_RUNNING); } int value;