From 7a349d619256d44832c8818df248aa1894a88cb5 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 18 Dec 2022 16:30:06 +0900 Subject: [PATCH] TEVD DOM changes committing to the physical disk --- tsvm_core/src/net/torvald/tsvm/VM.kt | 1 + tsvm_core/src/net/torvald/tsvm/VMWatchdog.kt | 56 +++++++++++++++++++ .../torvald/tsvm/peripheral/TevdDiskDrive.kt | 50 +++++------------ .../src/net/torvald/tsvm/vdc/V2kRunTest.kt | 2 +- .../src/net/torvald/tsvm/AppLoader.java | 11 ++-- .../src/net/torvald/tsvm/VMEmuExecutable.kt | 13 +++-- tsvm_executable/src/net/torvald/tsvm/VMGUI.kt | 4 +- 7 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 tsvm_core/src/net/torvald/tsvm/VMWatchdog.kt diff --git a/tsvm_core/src/net/torvald/tsvm/VM.kt b/tsvm_core/src/net/torvald/tsvm/VM.kt index 019f31a..08fcffd 100644 --- a/tsvm_core/src/net/torvald/tsvm/VM.kt +++ b/tsvm_core/src/net/torvald/tsvm/VM.kt @@ -25,6 +25,7 @@ class VM( val worldInterface: WorldInterface, val roms: Array, // first ROM must contain the BIOS _peripheralSlots: Int = 8, + val watchdogs: HashMap ) { val peripheralSlots = _peripheralSlots.coerceIn(1,8) diff --git a/tsvm_core/src/net/torvald/tsvm/VMWatchdog.kt b/tsvm_core/src/net/torvald/tsvm/VMWatchdog.kt new file mode 100644 index 0000000..dccad6f --- /dev/null +++ b/tsvm_core/src/net/torvald/tsvm/VMWatchdog.kt @@ -0,0 +1,56 @@ +package net.torvald.tsvm + +import com.badlogic.gdx.utils.Queue +import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil +import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VirtualDisk +import java.io.File + +/** + * Created by minjaesong on 2022-12-18. + */ +abstract class VMWatchdog { + + /** Seconds between sleep */ + abstract val interval: Float + protected var akku = 0f + + open fun update(delta: Float) { + akku += delta + while (akku > interval) { + consumeMessages() + println("[${this.javaClass.simpleName}] boop!") + akku -= interval + } + } + + protected abstract fun consumeMessages() + abstract fun addMessage(message: Array) + +} + + +object TevdSyncWatchdog : VMWatchdog() { + override val interval = 5f + + private val messageQueue = ArrayList>() + + override fun consumeMessages() { + synchronized(this) { + messageQueue.forEach { (outfile, dom) -> + VDUtil.dumpToRealMachine(dom, outfile) + println("[${this.javaClass.simpleName}] dump ${outfile.path}") + } + messageQueue.clear() + } + } + + override fun addMessage(message: Array) { + val file = message[0] as File + val dom = message[1] as VirtualDisk + + val hasDup = messageQueue.fold(false) { acc, pair -> acc or (pair.first.path == file.path) } + if (!hasDup) { + messageQueue.add(file to dom) + } + } +} \ No newline at end of file diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt index 3c38dfc..c223da6 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt @@ -37,42 +37,18 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please private var blockSendBuffer = ByteArray(1) private var blockSendCount = 0 - - private val hasChanges = AtomicBoolean(false) - + init { statusCode.set(TestDiskDrive.STATE_CODE_STANDBY) if (!tevdPath.exists()) { throw FileNotFoundException("Disk file '${theTevdPath}' not found") } - - Thread { - while (vm.isRunning) { - println("TevdCommitWatchdog ping") - if (hasChanges.compareAndExchangeAcquire(true, false)) { - printdbg("Disk has changes, committing... $theTevdPath") - commit() - } - else { - printdbg("Disk has no changes, skipping... $theTevdPath") - } - Thread.sleep(1000L * COMMIT_INTERVAL) - } - }.let { - it.start() - vm.contexts.add(it) - } } - companion object { - /** How often the changes in DOM (disk object model) should be saved to the physical drive when there are changes. Seconds. */ - const val COMMIT_INTERVAL = 5 - } - - fun commit() { - VDUtil.dumpToRealMachine(DOM, tevdPath) + fun notifyDiskCommit() { + vm.watchdogs["TEVD_SYNC"]?.addMessage(arrayOf(tevdPath, DOM)) } @@ -140,8 +116,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t writeMode = false appendMode = false - printdbg("Raising HasChanges flag (end of write)") - hasChanges.set(true) + printdbg("Notifying disk commit (end of write)") + notifyDiskCommit() } } else { @@ -229,8 +205,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t } try { file.delete() - printdbg("Raising HasChanges flag (file deleted)") - hasChanges.set(true) + printdbg("Notifying disk commit (file deleted)") + notifyDiskCommit() } catch (e: SecurityException) { statusCode.set(TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR) @@ -365,8 +341,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t val status = file.mkdir() statusCode.set(if (status) 0 else 1) if (status) { - printdbg("Raising HasChanges flag (mkdir)") - hasChanges.set(true) + printdbg("Notifying disk commit (mkdir)") + notifyDiskCommit() } } catch (e: SecurityException) { @@ -386,8 +362,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t val f1 = file.createNewFile() statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED) if (f1) { - printdbg("Raising HasChanges flag (mkfile)") - hasChanges.set(true) + printdbg("Notifying disk commit (mkfile)") + notifyDiskCommit() } return } @@ -411,8 +387,8 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t val f1 = file.setLastModified(vm.worldInterface.currentTimeInMills()) statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED) if (f1) { - printdbg("Raising HasChanges flag (touch)") - hasChanges.set(true) + printdbg("Notifying disk commit (touch)") + notifyDiskCommit() } return } diff --git a/tsvm_core/src/net/torvald/tsvm/vdc/V2kRunTest.kt b/tsvm_core/src/net/torvald/tsvm/vdc/V2kRunTest.kt index 6155cf7..67cc45a 100644 --- a/tsvm_core/src/net/torvald/tsvm/vdc/V2kRunTest.kt +++ b/tsvm_core/src/net/torvald/tsvm/vdc/V2kRunTest.kt @@ -15,7 +15,7 @@ import net.torvald.tsvm.peripheral.GraphicsAdapter class V2kRunTest : ApplicationAdapter() { - val vm = VM("./assets", 64.kB(), TheRealWorld(), arrayOf()) + val vm = VM("./assets", 64.kB(), TheRealWorld(), arrayOf(), watchdogs = hashMapOf()) lateinit var gpu: GraphicsAdapter lateinit var batch: SpriteBatch diff --git a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java index af8884a..c6ad0ba 100644 --- a/tsvm_executable/src/net/torvald/tsvm/AppLoader.java +++ b/tsvm_executable/src/net/torvald/tsvm/AppLoader.java @@ -8,6 +8,7 @@ import kotlin.collections.CollectionsKt; import net.torvald.tsvm.peripheral.*; import java.io.File; +import java.util.HashMap; public class AppLoader { @@ -29,6 +30,8 @@ public class AppLoader { appConfig.setWindowedMode(WIDTH, HEIGHT); + HashMap watchdogs = new HashMap<>(); + watchdogs.put("TEVD_SYNC", TevdSyncWatchdog.INSTANCE); String diskPath = "assets/disk0"; @@ -36,11 +39,11 @@ public class AppLoader { // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, BasicRom.INSTANCE}); // VM vm = new VM(64 << 10, new TheRealWorld(), new VMProgramRom[]{OEMBios.INSTANCE, BasicRom.INSTANCE}); -// VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}, 2); +// VM vm = new VM("./assets", 64 << 10, new TheRealWorld(), new VMProgramRom[]{TandemBios.INSTANCE, BasicRom.INSTANCE}, 2, watchdogs); // VM vm = new VM(128 << 10, new TheRealWorld(), new VMProgramRom[]{BasicBios.INSTANCE, WPBios.INSTANCE}); - VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}, 8); -// VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{OpenBios.INSTANCE}, 8); -// VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}, 8); + VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{TsvmBios.INSTANCE}, 8, watchdogs); +// VM vm = new VM("./assets", 8192 << 10, new TheRealWorld(), new VMProgramRom[]{OpenBios.INSTANCE}, 8, watchdogs); +// VM pipvm = new VM("./assets", 4096, new TheRealWorld(), new VMProgramRom[]{PipBios.INSTANCE, PipROM.INSTANCE}, 8, watchdogs); vm.getIO().getBlockTransferPorts()[0].attachDevice(new TestDiskDrive(vm, 0, diskPath)); vm.getIO().getBlockTransferPorts()[1].attachDevice(new HttpModem(vm, 1024, -1)); diff --git a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt index e77db44..bc7218a 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt @@ -5,14 +5,10 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.graphics.* import com.badlogic.gdx.graphics.g2d.SpriteBatch -import com.badlogic.gdx.utils.GdxRuntimeException -import com.badlogic.gdx.utils.JsonReader import com.badlogic.gdx.utils.JsonValue import com.badlogic.gdx.utils.JsonWriter -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch import net.torvald.terrarum.FlippingSpriteBatch import net.torvald.terrarum.imagefont.TinyAlphNum import net.torvald.terrarum.utils.JsonFetcher @@ -64,6 +60,9 @@ class VMEmuExecutableWrapper(val windowWidth: Int, val windowHeight: Int, var pa */ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: Int, var panelsY: Int, val diskPathRoot: String) : ApplicationAdapter() { + val TEVD_SYNC = TevdSyncWatchdog + + val watchdogs = hashMapOf("TEVD_SYNC" to TEVD_SYNC) private data class VMRunnerInfo(val vm: VM, val name: String) @@ -235,7 +234,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: super.render() - val dt = Gdx.graphics.rawDeltaTime + val dt = Gdx.graphics.deltaTime updateAkku += dt var i = 0L @@ -246,6 +245,8 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: } renderGame(dt) + + watchdogs.forEach { (_, watchdog) -> watchdog.update(dt) } } private fun reboot(vm: VM) { @@ -487,7 +488,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: val cardslots = json.getInt("cardslots") val roms = json.get("roms").iterator().map { VMProgramRom(it.asString()) }.toTypedArray() - val vm = VM(assetsDir, ramsize, TheRealWorld(), roms, cardslots) + val vm = VM(assetsDir, ramsize, TheRealWorld(), roms, cardslots, watchdogs) // install peripherals listOf("com1", "com2", "com3", "com4").map { json.get(it) }.forEachIndexed { index, jsonValue -> diff --git a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt index d7f2e18..b45f316 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt @@ -144,7 +144,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe super.render() - val dt = Gdx.graphics.rawDeltaTime + val dt = Gdx.graphics.deltaTime updateAkku += dt var i = 0L @@ -155,6 +155,8 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe } renderGame(dt) + + vm.watchdogs.forEach { (_, watchdog) -> watchdog.update(dt) } } private fun updateGame(delta: Float) {