mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-03-19 01:48:12 +00:00
Several improvements to the computer thread rework
- TimeoutState uses nanoseconds rather than milliseconds. While this is slightly less efficient on Windows, it's a) not the bottleneck of Lua execution and b) we need a monotonic counter, otherwise we could fail to terminate computers if the time changes. - Add an exception handler to all threads. - Document several classes a little better - I'm not sure how useful all of these are, but _hopefully_ it'll make the internals a little more accessible.
This commit is contained in:
parent
3e28f79ce9
commit
c78adb2cdc
@ -225,7 +225,6 @@ final class ComputerExecutor
|
||||
*/
|
||||
void abort()
|
||||
{
|
||||
// TODO: We need to test this much more thoroughly.
|
||||
ILuaMachine machine = this.machine;
|
||||
if( machine != null ) machine.close();
|
||||
|
||||
|
@ -18,7 +18,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for external APIs.
|
||||
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs.
|
||||
*
|
||||
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||
* @see ILuaAPIFactory
|
||||
|
@ -24,8 +24,6 @@ import static dan200.computercraft.core.computer.TimeoutState.TIMEOUT;
|
||||
*
|
||||
* This is split into two components: the {@link TaskRunner}s, which pull an executor from the queue and execute it, and
|
||||
* a single {@link Monitor} which observes all runners and kills them if they are behaving badly.
|
||||
*
|
||||
* TODO: Flesh out the documentation here.
|
||||
*/
|
||||
public class ComputerThread
|
||||
{
|
||||
@ -95,7 +93,7 @@ public class ComputerThread
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to stop the computer thread
|
||||
* Attempt to stop the computer thread. This interrupts each runner, and clears the task queue.
|
||||
*/
|
||||
public static void stop()
|
||||
{
|
||||
@ -160,7 +158,7 @@ public class ComputerThread
|
||||
|
||||
// If we're still within normal execution times (TIMEOUT) or soft abort (ABORT_TIMEOUT),
|
||||
// then we can let the Lua machine do its work.
|
||||
long afterStart = executor.timeout.milliSinceStart();
|
||||
long afterStart = executor.timeout.nanoSinceStart();
|
||||
long afterHardAbort = afterStart - TIMEOUT - ABORT_TIMEOUT;
|
||||
if( afterHardAbort < 0 ) continue;
|
||||
|
||||
@ -168,7 +166,7 @@ public class ComputerThread
|
||||
executor.timeout.hardAbort();
|
||||
executor.abort();
|
||||
|
||||
if( afterHardAbort >= ABORT_TIMEOUT + ABORT_TIMEOUT )
|
||||
if( afterHardAbort >= ABORT_TIMEOUT * 2 )
|
||||
{
|
||||
// If we've hard aborted and interrupted, and we're still not dead, then mark the runner
|
||||
// as dead, finish off the task, and spawn a new runner.
|
||||
@ -206,6 +204,10 @@ public class ComputerThread
|
||||
|
||||
/**
|
||||
* Pulls tasks from the {@link #computersActive} queue and runs them.
|
||||
*
|
||||
* This is responsible for running the {@link ComputerExecutor#work()}, {@link ComputerExecutor#beforeWork()} and
|
||||
* {@link ComputerExecutor#afterWork()} functions. Everything else is either handled by the executor, timeout
|
||||
* state or monitor.
|
||||
*/
|
||||
private static final class TaskRunner implements Runnable
|
||||
{
|
||||
|
@ -6,10 +6,28 @@
|
||||
|
||||
package dan200.computercraft.core.computer;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* {@link IComputerOwned} marks objects which are known to belong to a computer.
|
||||
*
|
||||
* The primary purpose of this is to allow Plethora (and potentially other mods) to run the various tracking methods
|
||||
* on {@link Computer}.
|
||||
*
|
||||
* You can generally assume {@link IComputerAccess} implements this interface, though you should always check first.
|
||||
*
|
||||
* @see dan200.computercraft.core.apis.ComputerAccess
|
||||
* @see dan200.computercraft.shared.peripheral.modem.wired.WiredModemPeripheral and the peripheral wrapper
|
||||
*/
|
||||
public interface IComputerOwned
|
||||
{
|
||||
/**
|
||||
* Get the computer associated with this object
|
||||
*
|
||||
* @return The associated object, or {@code null} if none is known.
|
||||
*/
|
||||
@Nullable
|
||||
Computer getComputer();
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
package dan200.computercraft.core.computer;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Used to measure how long a computer has executed for, and thus the relevant timeout states.
|
||||
*
|
||||
@ -26,28 +28,22 @@ package dan200.computercraft.core.computer;
|
||||
public final class TimeoutState
|
||||
{
|
||||
/**
|
||||
* The total time a task is allowed to run before aborting in milliseconds
|
||||
* The total time a task is allowed to run before aborting in nanoseconds
|
||||
*/
|
||||
static final long TIMEOUT = 7000;
|
||||
static final long TIMEOUT = TimeUnit.MILLISECONDS.toNanos( 7000 );
|
||||
|
||||
/**
|
||||
* The time the task is allowed to run after each abort in milliseconds
|
||||
* The time the task is allowed to run after each abort in nanoseconds
|
||||
*/
|
||||
static final long ABORT_TIMEOUT = 1500;
|
||||
static final long ABORT_TIMEOUT = TimeUnit.MILLISECONDS.toNanos( 1500 );
|
||||
|
||||
public static final String ABORT_MESSAGE = "Too long without yielding";
|
||||
|
||||
private volatile boolean softAbort;
|
||||
private volatile boolean hardAbort;
|
||||
|
||||
private long milliTime;
|
||||
private long nanoTime;
|
||||
|
||||
long milliSinceStart()
|
||||
{
|
||||
return System.currentTimeMillis() - milliTime;
|
||||
}
|
||||
|
||||
long nanoSinceStart()
|
||||
{
|
||||
return System.nanoTime() - nanoTime;
|
||||
@ -58,7 +54,7 @@ public final class TimeoutState
|
||||
*/
|
||||
public boolean isSoftAborted()
|
||||
{
|
||||
return softAbort || (softAbort = (System.currentTimeMillis() - milliTime) >= TIMEOUT);
|
||||
return softAbort || (softAbort = (System.nanoTime() - nanoTime) >= TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,7 +79,6 @@ public final class TimeoutState
|
||||
void reset()
|
||||
{
|
||||
softAbort = hardAbort = false;
|
||||
milliTime = System.currentTimeMillis();
|
||||
nanoTime = System.nanoTime();
|
||||
}
|
||||
}
|
||||
|
@ -99,11 +99,8 @@ public class CobaltLuaMachine implements ILuaMachine
|
||||
return;
|
||||
}
|
||||
|
||||
if( hasSoftAbort && !timeout.isHardAborted() )
|
||||
{
|
||||
// If we have fired our soft abort, but we haven't been hard aborted then everything is OK.
|
||||
return;
|
||||
}
|
||||
// If we have fired our soft abort, but we haven't been hard aborted then everything is OK.
|
||||
if( hasSoftAbort ) return;
|
||||
|
||||
hasSoftAbort = true;
|
||||
throw new LuaError( TimeoutState.ABORT_MESSAGE );
|
||||
@ -157,7 +154,7 @@ public class CobaltLuaMachine implements ILuaMachine
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAPI( ILuaAPI api )
|
||||
public void addAPI( @Nonnull ILuaAPI api )
|
||||
{
|
||||
// Add the methods of an API to the global table
|
||||
LuaTable table = wrapLuaObject( api );
|
||||
@ -169,7 +166,7 @@ public class CobaltLuaMachine implements ILuaMachine
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBios( InputStream bios )
|
||||
public void loadBios( @Nonnull InputStream bios )
|
||||
{
|
||||
// Begin executing a file (ie, the bios)
|
||||
if( m_mainRoutine != null ) return;
|
||||
|
@ -7,18 +7,61 @@
|
||||
package dan200.computercraft.core.lua;
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import dan200.computercraft.api.lua.ILuaObject;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Represents a machine which will execute Lua code. Technically this API is flexible enough to support many languages,
|
||||
* but you'd need a way to provide alternative ROMs, BIOSes, etc...
|
||||
*
|
||||
* There should only be one concrete implementation at any one time, which is currently {@link CobaltLuaMachine}. If
|
||||
* external mod authors are interested in registering their own machines, we can look into how we can provide some
|
||||
* mechanism for registering these.
|
||||
*
|
||||
* This should provide implementations of {@link dan200.computercraft.api.lua.ILuaContext}, and the ability to convert
|
||||
* {@link ILuaObject}s into something the VM understands, as well as handling method calls.
|
||||
*/
|
||||
public interface ILuaMachine
|
||||
{
|
||||
void addAPI( ILuaAPI api );
|
||||
/**
|
||||
* Inject an API into the global environment of this machine. This should construct an object, as it would for any
|
||||
* {@link ILuaObject} and set it to all names in {@link ILuaAPI#getNames()}.
|
||||
*
|
||||
* Called before {@link #loadBios(InputStream)}.
|
||||
*
|
||||
* @param api The API to register.
|
||||
*/
|
||||
void addAPI( @Nonnull ILuaAPI api );
|
||||
|
||||
void loadBios( InputStream bios );
|
||||
/**
|
||||
* Create a function from the provided program, and set it up to run when {@link #handleEvent(String, Object[])} is
|
||||
* called
|
||||
*
|
||||
* @param bios The stream containing the boot program.
|
||||
*/
|
||||
void loadBios( @Nonnull InputStream bios );
|
||||
|
||||
void handleEvent( String eventName, Object[] arguments );
|
||||
/**
|
||||
* Resume the machine, either starting or resuming the coroutine.
|
||||
*
|
||||
* @param eventName The name of the event. This is {@code null} when first starting the machine. Note, this may
|
||||
* do nothing if it does not match the event filter.
|
||||
* @param arguments The arguments for this event.
|
||||
*/
|
||||
void handleEvent( @Nullable String eventName, @Nullable Object[] arguments );
|
||||
|
||||
/**
|
||||
* If this machine has finished executing, either due to an error or it just shutting down.
|
||||
*
|
||||
* @return If this machine is finished.
|
||||
*/
|
||||
boolean isFinished();
|
||||
|
||||
/**
|
||||
* Close the Lua machine, aborting any running functions and deleting the internal state.
|
||||
*/
|
||||
void close();
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
@ -58,6 +59,7 @@ public final class ThreadUtils
|
||||
return new ThreadFactoryBuilder()
|
||||
.setDaemon( true )
|
||||
.setNameFormat( group.getName().replace( "%", "%%" ) + "-%d" )
|
||||
.setUncaughtExceptionHandler( ( t, e ) -> ComputerCraft.log.error( "Exception in thread " + t.getName(), e ) )
|
||||
.setThreadFactory( x -> new Thread( group, x ) );
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user