diff --git a/assets/DOSBOOT.tevd b/assets/DOSBOOT.tevd new file mode 100644 index 0000000..93eb572 Binary files /dev/null and b/assets/DOSBOOT.tevd differ diff --git a/assets/DOSBOOT.tevd.original b/assets/DOSBOOT.tevd.original new file mode 100644 index 0000000..93eb572 Binary files /dev/null and b/assets/DOSBOOT.tevd.original differ diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt index 0cca5d5..1865f63 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/BlockTransferInterface.kt @@ -1,11 +1,13 @@ package net.torvald.tsvm.peripheral +import java.util.concurrent.atomic.AtomicBoolean + abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolean) { protected var recipient: BlockTransferInterface? = null - @Volatile var ready = true - @Volatile var busy = false + @Volatile val ready = AtomicBoolean(true) + @Volatile val busy = AtomicBoolean(false) @Volatile var statusCode = 0 @@ -17,8 +19,8 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea device?.recipient = this } - open fun areYouReady(): Boolean = recipient?.ready ?: false - open fun areYouBusy(): Boolean = recipient?.busy ?: false + open fun areYouReady(): Boolean = recipient?.ready?.get() ?: false + open fun areYouBusy(): Boolean = recipient?.busy?.get() ?: false /** Writes a thing to the recipient. * A method exposed to outside of the box @@ -27,16 +29,16 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea /** The actual implementation */ fun startSend() { //if (areYouReady()) { - busy = true - ready = false + busy.setRelease(true) + ready.setRelease(false) recipient?.let { this.blockSize = startSendImpl(it) //println("[BlockTransferInterface.startSend()] recipients blocksize = ${this.blockSize}") } - busy = false - ready = true + busy.setRelease(false) + ready.setRelease(true) //} //else { // throw IOException("${this.javaClass.canonicalName}: Device '${recipient?.javaClass?.canonicalName}' is not ready to receive") @@ -55,12 +57,12 @@ abstract class BlockTransferInterface(val isMaster: Boolean, val isSlave: Boolea abstract fun writeoutImpl(inputData: ByteArray) /** The actual implementation; must be called by a sender class */ fun writeout(inputData: ByteArray) { - busy = true - ready = false + busy.setRelease(true) + ready.setRelease(false) blockSize = minOf(inputData.size, BLOCK_SIZE) writeoutImpl(inputData) - busy = false - ready = true + busy.setRelease(false) + ready.setRelease(true) } abstract fun hasNext(): Boolean open fun doYouHaveNext(): Boolean = recipient?.hasNext() ?: false diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index b246b7f..a9d7db7 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -57,7 +57,7 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: } } - private val DBGPRN = true + private val DBGPRN = false private fun printdbg(msg: Any) { if (DBGPRN) println("[TestDiskDrive] $msg") diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt index 9c1b250..d1d4df0 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt @@ -4,11 +4,12 @@ import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil import net.torvald.tsvm.VM import java.io.* import java.util.* +import java.util.concurrent.atomic.AtomicBoolean /** * Created by minjaesong on 2022-12-15. */ -class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val diskUUIDstr: String) : BlockTransferInterface(false, true) { +class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val theTevdPath: String, val diskUUIDstr: String) : BlockTransferInterface(false, true) { private val DBGPRN = true @@ -35,6 +36,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis private var blockSendBuffer = ByteArray(1) private var blockSendCount = 0 + private val hasChanges = AtomicBoolean(false) init { statusCode = TestDiskDrive.STATE_CODE_STANDBY @@ -42,12 +44,28 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis if (!tevdPath.exists()) { throw FileNotFoundException("Disk file '${theTevdPath}' not found") } + + Thread { + while (vm.isRunning) { + 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 = 30 + const val COMMIT_INTERVAL = 5 } fun commit() { @@ -116,6 +134,8 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis writeMode = false appendMode = false + + hasChanges.getAndSet(true) } } else { @@ -142,7 +162,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis else if (inputString.startsWith("DEVTYP\u0017")) recipient?.writeout(TestDiskDrive.composePositiveAns("STOR")) else if (inputString.startsWith("DEVNAM\u0017")) - recipient?.writeout(TestDiskDrive.composePositiveAns("Testtec Virtual Disk Drive")) + recipient?.writeout(TestDiskDrive.composePositiveAns("Generic Disk Drive")) else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) { if (fileOpen) { @@ -181,6 +201,11 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis statusCode = TestDiskDrive.STATE_CODE_NO_SUCH_FILE_EXISTS return } + else if (DOM.isReadOnly && (openMode == 'W' || openMode == 'A')) { + printdbg("! disk is read-only") + statusCode = TestDiskDrive.STATE_CODE_READ_ONLY + return + } statusCode = TestDiskDrive.STATE_CODE_STANDBY fileOpen = true @@ -198,6 +223,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis } try { file.delete() + hasChanges.getAndSet(true) } catch (e: SecurityException) { statusCode = TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR @@ -322,6 +348,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis try { val status = file.mkdir() statusCode = if (status) 0 else 1 + if (status) hasChanges.getAndSet(true) } catch (e: SecurityException) { statusCode = TestDiskDrive.STATE_CODE_SYSTEM_SECURITY_ERROR @@ -339,6 +366,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis try { val f1 = file.createNewFile() statusCode = if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED + if (f1) hasChanges.getAndSet(true) return } catch (e: IOException) { @@ -360,6 +388,7 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis try { val f1 = file.setLastModified(vm.worldInterface.currentTimeInMills()) statusCode = if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED + if (f1) hasChanges.getAndSet(true) return } catch (e: IOException) { @@ -427,6 +456,9 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis if (file.isFile) sb.append(file.name) else { + var filesCount = 0 + var dirsCount = 0 + sb.append("Current directory: ") sb.append(if (isRoot) "(root)" else file.path) sb.append('\n') @@ -442,16 +474,27 @@ class TevdDiskDrive(private val vm: VM, private val theTevdPath: String, val dis if (it.isDirectory) { sb.append("/") filenameLen += 1 + + dirsCount += 1 } sb.append(" ".repeat(40 - filenameLen)) if (it.isFile) { sb.append("${it.length()} B") + + filesCount += 1 } sb.append('\n') } + + sb.append("\n") + sb.append("\n$filesCount Files, $dirsCount, Directories") + sb.append("\nDisk used ${DOM.usedBytes} bytes") + sb.append("\n${DOM.capacity - DOM.usedBytes} bytes free") + if (DOM.isReadOnly) + sb.append("\nThe disk is read-only!") } return if (sb.last() == '\n') sb.substring(0, sb.lastIndex) else sb.toString() diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdFileDescriptor.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdFileDescriptor.kt index c3928b5..33a1681 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdFileDescriptor.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdFileDescriptor.kt @@ -24,10 +24,10 @@ class TevdFileDescriptor(val DOM: VirtualDisk, _pathstr: String) { val isFile: Boolean - get() = TODO() + get() = entryID.let { if (it == null) false else VDUtil.isFileFollowSymlink(DOM, it) } val isDirectory: Boolean - get() = TODO() + get() = entryID.let { if (it == null) false else VDUtil.isDirectoryFollowSymlink(DOM, it) } private var fileContent: EntryFile? = null @@ -63,6 +63,7 @@ class TevdFileDescriptor(val DOM: VirtualDisk, _pathstr: String) { fun delete() { fileContent = null + VDUtil.deleteFile(DOM, vdPath) } fun length(): Long {