1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-14 12:10:30 +00:00

Be a little more rigorous in KotlinLuaMachine's threading

This commit is contained in:
Jonathan Coates 2022-10-30 11:44:01 +00:00
parent 5ee5b11995
commit 1a87175ae7
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
4 changed files with 34 additions and 9 deletions

View File

@ -14,8 +14,6 @@ public enum UploadResult
CONSUMED, CONSUMED,
ERROR; ERROR;
public static final ITextComponent SUCCESS_TITLE = new TranslationTextComponent( "gui.computercraft.upload.success" );
public static final ITextComponent FAILED_TITLE = new TranslationTextComponent( "gui.computercraft.upload.failed" ); public static final ITextComponent FAILED_TITLE = new TranslationTextComponent( "gui.computercraft.upload.failed" );
public static final ITextComponent COMPUTER_OFF_MSG = new TranslationTextComponent( "gui.computercraft.upload.failed.computer_off" ); public static final ITextComponent COMPUTER_OFF_MSG = new TranslationTextComponent( "gui.computercraft.upload.failed.computer_off" );
public static final ITextComponent TOO_MUCH_MSG = new TranslationTextComponent( "gui.computercraft.upload.failed.too_much" ); public static final ITextComponent TOO_MUCH_MSG = new TranslationTextComponent( "gui.computercraft.upload.failed.too_much" );

View File

@ -116,8 +116,6 @@
"gui.computercraft.tooltip.turn_off.key": "Hold Ctrl+S", "gui.computercraft.tooltip.turn_off.key": "Hold Ctrl+S",
"gui.computercraft.tooltip.terminate": "Stop the currently running code", "gui.computercraft.tooltip.terminate": "Stop the currently running code",
"gui.computercraft.tooltip.terminate.key": "Hold Ctrl+T", "gui.computercraft.tooltip.terminate.key": "Hold Ctrl+T",
"gui.computercraft.upload.success": "Upload Succeeded",
"gui.computercraft.upload.success.msg": "%d files uploaded.",
"gui.computercraft.upload.failed": "Upload Failed", "gui.computercraft.upload.failed": "Upload Failed",
"gui.computercraft.upload.failed.computer_off": "You must turn the computer on before uploading files.", "gui.computercraft.upload.failed.computer_off": "You must turn the computer on before uploading files.",
"gui.computercraft.upload.failed.too_much": "Your files are too large to be uploaded.", "gui.computercraft.upload.failed.too_much": "Your files are too large to be uploaded.",

View File

@ -5,11 +5,9 @@ import dan200.computercraft.api.lua.ILuaContext
import dan200.computercraft.core.lua.ILuaMachine import dan200.computercraft.core.lua.ILuaMachine
import dan200.computercraft.core.lua.MachineEnvironment import dan200.computercraft.core.lua.MachineEnvironment
import dan200.computercraft.core.lua.MachineResult import dan200.computercraft.core.lua.MachineResult
import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.InputStream import java.io.InputStream
import kotlin.coroutines.CoroutineContext
/** /**
* An [ILuaMachine] which runs Kotlin functions instead. * An [ILuaMachine] which runs Kotlin functions instead.
@ -26,7 +24,7 @@ abstract class KotlinLuaMachine(environment: MachineEnvironment) : ILuaMachine,
queueEvent(eventName, arguments) queueEvent(eventName, arguments)
} else { } else {
val task = getTask() val task = getTask()
if (task != null) CoroutineScope(Dispatchers.Unconfined + CoroutineName("Computer")).launch { task() } if (task != null) CoroutineScope(NeverDispatcher() + CoroutineName("Computer")).launch { task() }
} }
return MachineResult.OK return MachineResult.OK
@ -38,4 +36,20 @@ abstract class KotlinLuaMachine(environment: MachineEnvironment) : ILuaMachine,
* Get the next task to execute on this computer. * Get the next task to execute on this computer.
*/ */
protected abstract fun getTask(): (suspend KotlinLuaMachine.() -> Unit)? protected abstract fun getTask(): (suspend KotlinLuaMachine.() -> Unit)?
/**
* A [CoroutineDispatcher] which only allows resuming from the computer thread. In practice, this means the only
* way to yield is with [pullEvent].
*/
private class NeverDispatcher : CoroutineDispatcher() {
private val expectedGroup = Thread.currentThread().threadGroup
override fun dispatch(context: CoroutineContext, block: Runnable) {
if (Thread.currentThread().threadGroup != expectedGroup) {
throw UnsupportedOperationException("Cannot perform arbitrary yields")
}
block.run()
}
}
} }

View File

@ -4,9 +4,11 @@ import dan200.computercraft.api.lua.ILuaAPI
import dan200.computercraft.api.lua.ILuaContext import dan200.computercraft.api.lua.ILuaContext
import dan200.computercraft.api.lua.MethodResult import dan200.computercraft.api.lua.MethodResult
import dan200.computercraft.api.lua.ObjectArguments import dan200.computercraft.api.lua.ObjectArguments
import dan200.computercraft.core.apis.OSAPI
import dan200.computercraft.core.apis.PeripheralAPI import dan200.computercraft.core.apis.PeripheralAPI
import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.time.Duration
/** /**
* The context for tasks which consume Lua objects. * The context for tasks which consume Lua objects.
@ -40,6 +42,19 @@ interface LuaTaskContext {
/** Call a peripheral method. */ /** Call a peripheral method. */
suspend fun LuaTaskContext.callPeripheral(name: String, method: String, vararg args: Any?): Array<out Any?>? = suspend fun LuaTaskContext.callPeripheral(name: String, method: String, vararg args: Any?): Array<out Any?>? =
getApi<PeripheralAPI>().call(context, ObjectArguments(name, method, *args)).await() getApi<PeripheralAPI>().call(context, ObjectArguments(name, method, *args)).await()
/**
* Sleep for the given duration. This uses the internal computer clock, so won't be accurate.
*/
suspend fun LuaTaskContext.sleep(duration: Duration) {
val timer = getApi<OSAPI>().startTimer(duration.inWholeMilliseconds / 1000.0)
while (true) {
val event = pullEvent("timer")
if (event[0] == "timer" && event[1] is Number && (event[1] as Number).toInt() == timer) {
return
}
}
}
} }
/** Get a registered API. */ /** Get a registered API. */