From 927c9a27ac674b0f400f5807d466798379a66a64 Mon Sep 17 00:00:00 2001 From: firda-cze Date: Sun, 10 Feb 2019 18:49:34 +0100 Subject: [PATCH] boot from archive --- src/kOS.Safe/Execution/CPU.cs | 23 +++++++-- .../Execution/YieldFinishedCompile.cs | 47 ++++++++----------- .../Execution/YieldFinishedCompileBoot.cs | 27 +++++++++++ ...or.cs => YieldFinishedThreadedDetector.cs} | 37 ++++++++++----- src/kOS.Safe/kOS.Safe.csproj | 5 +- 5 files changed, 95 insertions(+), 44 deletions(-) create mode 100644 src/kOS.Safe/Execution/YieldFinishedCompileBoot.cs rename src/kOS.Safe/Execution/{YiedFinishedThreadedDetector.cs => YieldFinishedThreadedDetector.cs} (75%) diff --git a/src/kOS.Safe/Execution/CPU.cs b/src/kOS.Safe/Execution/CPU.cs index e3feb0c09..fc2e7dbfd 100644 --- a/src/kOS.Safe/Execution/CPU.cs +++ b/src/kOS.Safe/Execution/CPU.cs @@ -136,15 +136,13 @@ public void Boot() shared.Screen.Print(bootMessage); } - if (!shared.Processor.CheckCanBoot()) return; - VolumePath path = shared.Processor.BootFilePath; // Check to make sure the boot file name is valid, and then that the boot file exists. if (path == null) { SafeHouse.Logger.Log("Boot file name is empty, skipping boot script"); } - else + else if (shared.Processor.CheckCanBoot()) { // Boot is only called once right after turning the processor on, // the volume cannot yet have been changed from that set based on @@ -176,6 +174,25 @@ public void Boot() } } + else //cannot boot right now + { + shared.Screen?.Print(string.Format(" \nWaiting for connection to boot from {0}.\n \n", path)); + var bootContext = "program"; + shared.ScriptHandler.ClearContext(bootContext); + IProgramContext programContext = SwitchToProgramContext(); + programContext.Silent = true; + + string bootCommand = string.Format("run \"{0}\".", path); + + var options = new CompilerOptions + { + LoadProgramsInSameAddressSpace = true, + FuncManager = shared.FunctionManager, + IsCalledFromRun = false + }; + + YieldProgram(YieldFinishedCompileBoot.RunScript(new BootGlobalPath(bootCommand), 1, bootCommand, bootContext, options)); + } } private void PushInterpreterContext() diff --git a/src/kOS.Safe/Execution/YieldFinishedCompile.cs b/src/kOS.Safe/Execution/YieldFinishedCompile.cs index adaf00314..6297cf680 100644 --- a/src/kOS.Safe/Execution/YieldFinishedCompile.cs +++ b/src/kOS.Safe/Execution/YieldFinishedCompile.cs @@ -1,4 +1,4 @@ -using kOS.Safe.Compilation; +using kOS.Safe.Compilation; using kOS.Safe.Encapsulation; using kOS.Safe.Persistence; using System.Collections.Generic; @@ -6,9 +6,9 @@ namespace kOS.Safe.Execution { - public class YieldFinishedCompile : YiedFinishedThreadedDetector + public class YieldFinishedCompile : YieldFinishedThreadedDetector { - private enum CompileMode + protected enum CompileMode { RUN = 0, LOAD = 1, @@ -28,9 +28,9 @@ private enum CompileMode private IProgramContext programContext; - private YieldFinishedCompile(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) + protected YieldFinishedCompile(CompileMode mode, GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) { - compileMode = CompileMode.RUN; + compileMode = mode; path = scriptPath; startLineNum = lineNumber; content = fileContent; @@ -38,19 +38,20 @@ private YieldFinishedCompile(GlobalPath scriptPath, int lineNumber, string fileC options = compilerOptions; } - public override void ThreadInitialize(SafeSharedObjects shared) + protected override bool ThreadInitialize() { if (compileMode != CompileMode.FILE) programContext = shared.Cpu.SwitchToProgramContext(); // only switch the context if executing codeParts = new List(); + return true; } - public override void ThreadExecute() + protected override void ThreadExecute() { codeParts = shared.ScriptHandler.Compile(path, startLineNum, content, contextId, options); } - public override void ThreadFinish() + protected override void ThreadFinish() { switch (compileMode) { @@ -76,27 +77,17 @@ public override void ThreadFinish() shared.Cpu.StopCompileStopwatch(); } - public static YieldFinishedCompile RunScript(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) - { - var ret = new YieldFinishedCompile(scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions); - ret.compileMode = CompileMode.RUN; - return ret; - } + public static YieldFinishedCompile RunScript(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) => + new YieldFinishedCompile(CompileMode.RUN, scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions); - public static YieldFinishedCompile LoadScript(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) - { - var ret = new YieldFinishedCompile(scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions); - ret.compileMode = CompileMode.LOAD; - return ret; - } + public static YieldFinishedCompile LoadScript(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) => + new YieldFinishedCompile(CompileMode.LOAD, scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions); - public static YieldFinishedCompile CompileScriptToFile(GlobalPath scriptPath, int lineNumber, string fileContent, CompilerOptions compilerOptions, Volume storageVolume, GlobalPath storagePath) - { - var ret = new YieldFinishedCompile(scriptPath, lineNumber, fileContent, string.Empty, compilerOptions); - ret.compileMode = CompileMode.FILE; - ret.volume = storageVolume; - ret.outPath = storagePath; - return ret; - } + public static YieldFinishedCompile CompileScriptToFile(GlobalPath scriptPath, int lineNumber, string fileContent, CompilerOptions compilerOptions, Volume storageVolume, GlobalPath storagePath) => + new YieldFinishedCompile(CompileMode.FILE, scriptPath, lineNumber, fileContent, string.Empty, compilerOptions) + { + volume = storageVolume, + outPath = storagePath + }; } } \ No newline at end of file diff --git a/src/kOS.Safe/Execution/YieldFinishedCompileBoot.cs b/src/kOS.Safe/Execution/YieldFinishedCompileBoot.cs new file mode 100644 index 000000000..80fb3c686 --- /dev/null +++ b/src/kOS.Safe/Execution/YieldFinishedCompileBoot.cs @@ -0,0 +1,27 @@ +using kOS.Safe.Compilation; +using kOS.Safe.Encapsulation; +using kOS.Safe.Persistence; +using System.Collections.Generic; +using System.Threading; + +namespace kOS.Safe.Execution +{ + public class YieldFinishedCompileBoot : YieldFinishedCompile + { + protected YieldFinishedCompileBoot(CompileMode mode, GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) : + base(mode, scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions) + { } + + protected override bool ThreadInitialize() + { + if (!shared.Processor.CheckCanBoot()) + return false; + shared.Screen?.Print("Booting ...\n"); + base.ThreadInitialize(); + return true; + } + + public static new YieldFinishedCompileBoot RunScript(GlobalPath scriptPath, int lineNumber, string fileContent, string contextIdentifier, CompilerOptions compilerOptions) => + new YieldFinishedCompileBoot(CompileMode.RUN, scriptPath, lineNumber, fileContent, contextIdentifier, compilerOptions); + } +} \ No newline at end of file diff --git a/src/kOS.Safe/Execution/YiedFinishedThreadedDetector.cs b/src/kOS.Safe/Execution/YieldFinishedThreadedDetector.cs similarity index 75% rename from src/kOS.Safe/Execution/YiedFinishedThreadedDetector.cs rename to src/kOS.Safe/Execution/YieldFinishedThreadedDetector.cs index eca80cd3f..df9904b1d 100644 --- a/src/kOS.Safe/Execution/YiedFinishedThreadedDetector.cs +++ b/src/kOS.Safe/Execution/YieldFinishedThreadedDetector.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +6,7 @@ namespace kOS.Safe.Execution { - public abstract class YiedFinishedThreadedDetector : YieldFinishedDetector + public abstract class YieldFinishedThreadedDetector : YieldFinishedDetector { private ManualResetEvent childThreadEvent; private Thread childThread; @@ -23,15 +23,23 @@ public override void Begin(SafeSharedObjects sharedObj) childThreadEvent = new ManualResetEvent(false); - ThreadInitialize(sharedObj); + TryStartThread(); + } - childThread = new Thread(DoThread); - childThread.IsBackground = true; - childThread.Start(); + private void TryStartThread() + { + if (ThreadInitialize()) + { + childThread = new Thread(DoThread); + childThread.IsBackground = true; + childThread.Start(); + } } public override bool IsFinished() { + // Thread may not be started yet, but this distinguishes between finished and not-started + // in case IsFinished() gets called multiple times even after it returns true if (childThreadEvent.WaitOne(0)) { childThread.Join(); @@ -46,6 +54,10 @@ public override bool IsFinished() childException = ex; } } + + // Remove the reference now, before we potentially (re)throw the exception + childThread = null; + // Note this is *deliberately* NOT an "else" of the above "if" even though // it looks like it should be. That is because the above IF clause can actually // alter this flag and if it does so it needs to fall through to here and do this. @@ -59,9 +71,12 @@ public override bool IsFinished() shared.Cpu.BreakExecution(false); throw childException; } - childThread = null; return true; } + // Try starting the thread now, if not started yet + if (childThread == null) + TryStartThread(); + return false; } @@ -82,8 +97,8 @@ private void DoThread() /// This method is executed before starting the child thread. It is called from the main thread and is not required /// to be thread safe with respect to KSP. /// - /// - public abstract void ThreadInitialize(SafeSharedObjects shared); + /// True if ready to start the thread (false if waiting for some condition, e.g. Processor.CheckCanBoot) + protected abstract bool ThreadInitialize(); /// /// @@ -96,12 +111,12 @@ private void DoThread() /// /// /// - public abstract void ThreadExecute(); + protected abstract void ThreadExecute(); /// /// This method is executed after the child thread is finished, when the CPU checks IsFinished. It is called from /// the main thread and is not required to be thread safe with respect to KSP. /// - public abstract void ThreadFinish(); + protected abstract void ThreadFinish(); } } diff --git a/src/kOS.Safe/kOS.Safe.csproj b/src/kOS.Safe/kOS.Safe.csproj index bfb446d4f..976a5a2e1 100644 --- a/src/kOS.Safe/kOS.Safe.csproj +++ b/src/kOS.Safe/kOS.Safe.csproj @@ -181,8 +181,9 @@ - + + @@ -319,4 +320,4 @@ --> - + \ No newline at end of file