mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-08 12:11:51 +09:00
preemption proof-of-concept
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package net.torvald.tsvm
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import net.torvald.UnsafeHelper
|
||||
import net.torvald.UnsafePtr
|
||||
import net.torvald.tsvm.peripheral.IOSpace
|
||||
@@ -19,6 +20,7 @@ class ErrorIllegalAccess(vm: VM, addr: Long) : RuntimeException("Segmentation fa
|
||||
*/
|
||||
|
||||
class VM(
|
||||
val assetsDir: String,
|
||||
_memsize: Long,
|
||||
val worldInterface: WorldInterface,
|
||||
val roms: Array<VMProgramRom?> // first ROM must contain the BIOS
|
||||
@@ -26,8 +28,10 @@ class VM(
|
||||
|
||||
val id = java.util.Random().nextInt()
|
||||
|
||||
internal val contexts = ArrayList<Thread>()
|
||||
|
||||
val memsize = minOf(USER_SPACE_SIZE, _memsize.toLong())
|
||||
private val MALLOC_UNIT = 64
|
||||
val MALLOC_UNIT = 64
|
||||
private val mallocBlockSize = (memsize / MALLOC_UNIT).toInt()
|
||||
|
||||
internal val usermem = UnsafeHelper.allocate(memsize)
|
||||
@@ -57,7 +61,15 @@ class VM(
|
||||
init()
|
||||
}
|
||||
|
||||
fun killAllContexts() {
|
||||
contexts.forEach { it.interrupt() }
|
||||
contexts.clear()
|
||||
}
|
||||
|
||||
fun init() {
|
||||
killAllContexts()
|
||||
|
||||
|
||||
peripheralTable[0] = PeripheralEntry(
|
||||
IOSpace(this),
|
||||
HW_RESERVE_SIZE,
|
||||
@@ -83,6 +95,7 @@ class VM(
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
killAllContexts()
|
||||
usermem.destroy()
|
||||
peripheralTable.forEach { it.peripheral?.dispose() }
|
||||
}
|
||||
@@ -151,6 +164,7 @@ class VM(
|
||||
|
||||
private val mallocMap = BitSet(mallocBlockSize)
|
||||
private val mallocSizes = HashMap<Int, Int>() // HashMap<Block Index, Block Count>
|
||||
var allocatedBlockCount = 0; private set
|
||||
|
||||
private fun findEmptySpace(blockSize: Int): Int? {
|
||||
var cursorHead = 0
|
||||
@@ -180,6 +194,7 @@ class VM(
|
||||
val allocBlocks = ceil(size.toDouble() / MALLOC_UNIT).toInt()
|
||||
val blockStart = findEmptySpace(allocBlocks) ?: throw OutOfMemoryError()
|
||||
|
||||
allocatedBlockCount += allocBlocks
|
||||
mallocSizes[blockStart] = allocBlocks
|
||||
return blockStart * MALLOC_UNIT
|
||||
}
|
||||
@@ -190,6 +205,7 @@ class VM(
|
||||
|
||||
mallocMap.set(index, index + count, false)
|
||||
mallocSizes.remove(index)
|
||||
allocatedBlockCount -= count
|
||||
}
|
||||
|
||||
internal data class VMNativePtr(val address: Int, val size: Int)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package net.torvald.tsvm
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.toUlong
|
||||
import java.nio.charset.Charset
|
||||
|
||||
@@ -140,10 +143,32 @@ class VMJSR223Delegate(val vm: VM) {
|
||||
}
|
||||
fun waitForMemChg(addr: Int, andMask: Int) = waitForMemChg(addr, andMask, 0)
|
||||
|
||||
fun getUsedMem() = vm.allocatedBlockCount * vm.MALLOC_UNIT
|
||||
}
|
||||
|
||||
class VMSerialDebugger(val vm: VM) {
|
||||
fun print(s: Any?) = System.out.print("$s")
|
||||
fun println(s: Any?) = System.out.println("$s")
|
||||
fun printerr(s: Any?) = System.err.println("$s")
|
||||
}
|
||||
|
||||
class Parallel(val vm: VM) {
|
||||
fun spawnNewContext(): VMRunner {
|
||||
return VMRunnerFactory(vm.assetsDir, vm, "js")
|
||||
}
|
||||
fun attachProgram(context: VMRunner, program: String): Thread {
|
||||
Thread { context.eval(program) }.let {
|
||||
vm.contexts.add(it)
|
||||
return it
|
||||
}
|
||||
}
|
||||
fun launch(thread: Thread) {
|
||||
thread.start()
|
||||
}
|
||||
fun suspend(thread: Thread) {
|
||||
thread.suspend()
|
||||
}
|
||||
fun resume(thread: Thread) {
|
||||
thread.resume()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import javax.script.ScriptEngineManager
|
||||
abstract class VMRunner(val extension: String) {
|
||||
abstract suspend fun executeCommand(command: String)
|
||||
abstract suspend fun evalGlobal(command: String)
|
||||
abstract fun eval(command: String)
|
||||
abstract fun close()
|
||||
}
|
||||
|
||||
@@ -65,6 +66,7 @@ object VMRunnerFactory {
|
||||
bind.putMember("base64", Base64Delegate)
|
||||
bind.putMember("com", SerialHelperDelegate(vm))
|
||||
bind.putMember("dma", DMADelegate(vm))
|
||||
bind.putMember("parallel", Parallel(vm))
|
||||
|
||||
val fr = FileReader("$assetsRoot/JS_INIT.js")
|
||||
val prg = fr.readText()
|
||||
@@ -83,6 +85,16 @@ object VMRunnerFactory {
|
||||
}
|
||||
}
|
||||
|
||||
override fun eval(command: String) {
|
||||
try {
|
||||
context.eval("js", encapsulateJS(sanitiseJS(command)))
|
||||
}
|
||||
catch (e: javax.script.ScriptException) {
|
||||
System.err.println("ScriptException from the script:")
|
||||
System.err.println(command.substring(0, minOf(1024, command.length)))
|
||||
throw e
|
||||
} }
|
||||
|
||||
override suspend fun evalGlobal(command: String) {
|
||||
context.eval("js", "\"use strict\";" + sanitiseJS(command))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user