From a72e2dd8381bacd3dc1778c31311ce66ec9db19a Mon Sep 17 00:00:00 2001 From: firda-cze Date: Fri, 30 Mar 2018 17:21:45 +0200 Subject: [PATCH 1/5] .editorconfig and .gitignore (vs and vim) --- .editorconfig | 7 +++++++ .gitignore | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..3bf781337 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*.cs] +indent_style = space +indent_size = 4 +charset = utf-8 +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false diff --git a/.gitignore b/.gitignore index 0b08299a8..d7a83ada7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # VisualStudio +.vs/ [Bb]in/ [Oo]bj/ *.suo @@ -12,6 +13,9 @@ packages/ # VisualStudio Code .vscode/ +# Vim +*.swp + # Unity [Ll]ibrary/ [Tt]emp/ @@ -36,4 +40,4 @@ netkan.exe *.ckan #zip files for archived art assets -*.zip \ No newline at end of file +*.zip From 064ff246c84e2ccd6eeb6ec4698f91abca78f35f Mon Sep 17 00:00:00 2001 From: firda-cze Date: Thu, 29 Mar 2018 21:34:36 +0200 Subject: [PATCH 2/5] better screen/terminal printouts during booting --- src/kOS.Safe/Execution/CPU.cs | 41 ++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/kOS.Safe/Execution/CPU.cs b/src/kOS.Safe/Execution/CPU.cs index 98396619e..3b7676027 100644 --- a/src/kOS.Safe/Execution/CPU.cs +++ b/src/kOS.Safe/Execution/CPU.cs @@ -1,4 +1,4 @@ -using kOS.Safe.Binding; +using kOS.Safe.Binding; using kOS.Safe.Callback; using kOS.Safe.Compilation; using kOS.Safe.Encapsulation; @@ -115,8 +115,12 @@ public void Boot() if (shared.Screen != null) { shared.Screen.ClearScreen(); - string bootMessage = string.Format("kOS Operating System\n" + "KerboScript v{0}\n(manual at {1})\n \n" + "Proceed.\n", - SafeHouse.Version, SafeHouse.DocumentationURL); + var bootMessage = string.Format( + "kOS Operating System\n" + + "KerboScript v{0}\n" + + "(manual at {1})\n", + SafeHouse.Version, + SafeHouse.DocumentationURL); List nags = Debug.GetPendingNags(); if (nags.Count > 0) { @@ -133,16 +137,27 @@ public void Boot() bootMessage += "##################################################\n"; shared.Processor.SetMode(Module.ProcessorModes.OFF); } + 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"); + + shared.Screen?.Print(" \n" + "Proceed.\n"); + } + else if (!shared.Processor.CheckCanBoot()) + { + shared.Screen?.Print(string.Format( + " \n" + + "Could not boot from {0}\n" + + "Probably no connection to home\n" + + " \n" + + "Proceed.\n", + path)); } else { @@ -155,9 +170,23 @@ public void Boot() if (file == null) { SafeHouse.Logger.Log(string.Format("Boot file \"{0}\" is missing, skipping boot script", path)); + + shared.Screen?.Print(string.Format( + " \n" + + "Could not boot from {0}\n" + + "The file is missing\n" + + " \n" + + "Proceed.\n", + path)); } else { + shared.Screen?.Print(string.Format( + " \n" + + "Booting from {0}\n" + + " \n", + path)); + var bootContext = "program"; shared.ScriptHandler.ClearContext(bootContext); IProgramContext programContext = SwitchToProgramContext(); @@ -173,7 +202,7 @@ public void Boot() }; YieldProgram(YieldFinishedCompile.RunScript(new BootGlobalPath(bootCommand), 1, bootCommand, bootContext, options)); - + } } } From aa69a0d670ab7c8cebe933f515c46e0e2a87b32b Mon Sep 17 00:00:00 2001 From: firda-cze Date: Thu, 29 Mar 2018 21:51:37 +0200 Subject: [PATCH 3/5] crutial changes from tester --- src/kOS.Safe/Compilation/PseudoNull.cs | 4 +- src/kOS.Safe/Execution/CPU.cs | 116 +++++++++++++------------ src/kOS.Safe/Execution/IStack.cs | 27 +++++- src/kOS.Safe/Execution/Stack.cs | 57 +++++++++++- 4 files changed, 145 insertions(+), 59 deletions(-) diff --git a/src/kOS.Safe/Compilation/PseudoNull.cs b/src/kOS.Safe/Compilation/PseudoNull.cs index ef19c828b..5d89602e9 100644 --- a/src/kOS.Safe/Compilation/PseudoNull.cs +++ b/src/kOS.Safe/Compilation/PseudoNull.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace kOS.Safe.Compilation { @@ -6,6 +6,8 @@ namespace kOS.Safe.Compilation // use this for a fake "type" to reperesent null: public class PseudoNull : IEquatable { + public static PseudoNull Instance { get; } = new PseudoNull(); + // all instances of PseudoNull should be considered identical: public override bool Equals(object o) { diff --git a/src/kOS.Safe/Execution/CPU.cs b/src/kOS.Safe/Execution/CPU.cs index 3b7676027..03c123125 100644 --- a/src/kOS.Safe/Execution/CPU.cs +++ b/src/kOS.Safe/Execution/CPU.cs @@ -16,41 +16,41 @@ namespace kOS.Safe.Execution { public class CPU : ICpu { - private enum Section + protected enum Section { Main = 1, Trigger = 2 } - private readonly IStack stack; - private readonly VariableScope globalVariables; - private Section currentRunSection; - private List triggerYields; - private List mainYields; - - private double currentTime; - private readonly SafeSharedObjects shared; - private readonly List contexts; - private ProgramContext currentContext; - private VariableScope savedPointers; - private int instructionsSoFarInUpdate; - private int instructionsPerUpdate; + protected readonly IStack stack; + protected readonly VariableScope globalVariables; + protected Section currentRunSection; + protected List triggerYields; + protected List mainYields; + + protected double currentTime; + protected readonly SafeSharedObjects shared; + protected readonly List contexts; + protected ProgramContext currentContext; + protected VariableScope savedPointers; + protected int instructionsSoFarInUpdate; + protected int instructionsPerUpdate; public int InstructionsThisUpdate { get { return instructionsSoFarInUpdate; } } // statistics - private double totalCompileTime; - - private double totalUpdateTime; - private double totalExecutionTime; - private double maxUpdateTime; - private double maxExecutionTime; - private Stopwatch instructionWatch = new Stopwatch(); - private Stopwatch updateWatch = new Stopwatch(); - private Stopwatch executionWatch = new Stopwatch(); - private Stopwatch compileWatch = new Stopwatch(); - private int maxMainlineInstructionsSoFar; - private readonly StringBuilder executeLog = new StringBuilder(); + protected double totalCompileTime; + + protected double totalUpdateTime; + protected double totalExecutionTime; + protected double maxUpdateTime; + protected double maxExecutionTime; + protected Stopwatch instructionWatch = new Stopwatch(); + protected Stopwatch updateWatch = new Stopwatch(); + protected Stopwatch executionWatch = new Stopwatch(); + protected Stopwatch compileWatch = new Stopwatch(); + protected int maxMainlineInstructionsSoFar; + protected readonly StringBuilder executeLog = new StringBuilder(); public int InstructionPointer { @@ -74,7 +74,7 @@ public int InstructionPointer /// The objects which have chosen to register themselves as IPopContextNotifyees /// to be told when popping a context (ending a program). /// - private List popContextNotifyees; + protected List popContextNotifyees; public CPU(SafeSharedObjects shared) { @@ -207,7 +207,7 @@ public void Boot() } } - private void PushInterpreterContext() + protected void PushInterpreterContext() { var interpreterContext = new ProgramContext(true); // initialize the context with an empty program @@ -215,7 +215,7 @@ private void PushInterpreterContext() PushContext(interpreterContext); } - private void PushContext(ProgramContext context) + protected void PushContext(ProgramContext context) { SafeHouse.Logger.Log("Pushing context staring with: " + context.GetCodeFragment(0).FirstOrDefault()); SaveAndClearPointers(); @@ -229,7 +229,7 @@ private void PushContext(ProgramContext context) } } - private void PopContext() + protected void PopContext() { SafeHouse.Logger.Log("Popping context " + contexts.Count); IsPoppingContext = true; @@ -295,7 +295,7 @@ public void RemovePopContextNotifyee(IPopContextNotifyee notifyee) popContextNotifyees.RemoveAll((item)=>(!item.IsAlive) || item.Target == notifyee); } - private void NotifyPopContextNotifyees(IProgramContext context) + protected void NotifyPopContextNotifyees(IProgramContext context) { // Notify them all: for (int i = 0; i < popContextNotifyees.Count; ++i) @@ -344,7 +344,7 @@ public object PopScopeStack(int howMany) return returnVal; } - private void PopFirstContext() + protected void PopFirstContext() { while (contexts.Count > 1) { @@ -421,7 +421,7 @@ public Opcode GetOpcodeAt(int instructionPtr) return currentContext.Program[instructionPtr]; } - private void SaveAndClearPointers() + protected void SaveAndClearPointers() { // Any global variable that ends in an asterisk (*) is a system pointer // that shouldn't be inherited by other program contexts. These sorts of @@ -443,7 +443,7 @@ private void SaveAndClearPointers() SafeHouse.Logger.Log(string.Format("Saving and removing {0} pointers", pointers.Count)); } - private void RestorePointers() + protected void RestorePointers() { // Pointer variables that were stashed by SaveAndClearPointers() get brought // back again by this method when returning to the previous programming @@ -552,7 +552,7 @@ public void YieldProgram(YieldFinishedDetector yieldTracker) yieldTracker.Begin(shared); } - private bool IsYielding() + protected bool IsYielding() { List yieldTrackers; @@ -581,8 +581,8 @@ private bool IsYielding() // are finished and we should still return that we are waiting: return yieldTrackers.Count > 0; } - - private void AbortAllYields() + + protected void AbortAllYields() { mainYields.Clear(); triggerYields.Clear(); @@ -651,7 +651,7 @@ public List GetCallTrace() /// /// /// - private Variable GetOrCreateVariable(string identifier) + protected Variable GetOrCreateVariable(string identifier) { Variable variable = GetVariable(identifier, false, true); if (variable == null) @@ -710,7 +710,7 @@ public string DumpStack() return stack.Dump(); } - private VariableScope GetCurrentScope() + protected VariableScope GetCurrentScope() { VariableScope currentScope = stack.GetCurrentScope(); if (currentScope == null) @@ -746,7 +746,7 @@ public List GetTriggerCallContexts(TriggerInfo trigger) /// Is it acceptable for the variable to /// not exist, in which case a null will be returned as the value. /// the value that was found - private Variable GetVariable(string identifier, bool barewordOkay = false, bool failOkay = false) + protected Variable GetVariable(string identifier, bool barewordOkay = false, bool failOkay = false) { identifier = identifier.ToLower(); Variable value = GetCurrentScope().GetNested(identifier); @@ -1251,7 +1251,7 @@ public void CancelCalledTriggers(TriggerInfo trigger) } } - public void KOSFixedUpdate(double deltaTime) + public virtual void KOSFixedUpdate(double deltaTime) { bool showStatistics = SafeHouse.Config.ShowStatistics; var executionElapsed = 0.0; @@ -1348,7 +1348,7 @@ public void KOSFixedUpdate(double deltaTime) } } - private void PreUpdateBindings() + protected void PreUpdateBindings() { if (shared.BindingMgr != null) { @@ -1356,7 +1356,7 @@ private void PreUpdateBindings() } } - private void PostUpdateBindings() + protected void PostUpdateBindings() { if (shared.BindingMgr != null) { @@ -1364,7 +1364,7 @@ private void PostUpdateBindings() } } - private void ProcessTriggers() + protected void ProcessTriggers() { if (currentContext.ActiveTriggerCount() <= 0) return; int oldCount = currentContext.Program.Count; @@ -1386,7 +1386,7 @@ private void ProcessTriggers() // will be invalid. Only execute the trigger if it still exists. if (currentContext.ContainsTrigger(trigger)) { - if (trigger is NoDelegate) + if (trigger.EntryPoint < 0 /* NoDelegate */) { // Don't bother calling it. Just declare it to be "done" with its default value. trigger.FinishCallback(new ScalarIntValue(0)); @@ -1436,7 +1436,7 @@ private void ProcessTriggers() currentContext.InstructionPointer = currentInstructionPointer; } - private void ContinueExecution(bool doProfiling) + protected virtual void ContinueExecution(bool doProfiling) { var executeNext = true; int howManyMainLine = 0; @@ -1478,7 +1478,7 @@ private void ContinueExecution(bool doProfiling) SafeHouse.Logger.Log(executeLog.ToString()); } - private bool ExecuteInstruction(ProgramContext context, bool doProfiling) + protected virtual bool ExecuteInstruction(ProgramContext context, bool doProfiling) { Opcode opcode = context.Program[context.InstructionPointer]; @@ -1537,7 +1537,7 @@ private bool ExecuteInstruction(ProgramContext context, bool doProfiling) } } - private void SkipCurrentInstructionId() + protected void SkipCurrentInstructionId() { if (currentContext.InstructionPointer >= (currentContext.Program.Count - 1)) return; @@ -1609,21 +1609,27 @@ public void ResetStatistics() maxExecutionTime = 0.0; maxMainlineInstructionsSoFar = 0; } - - private void PrintStatistics() + + protected void PrintStatistics() { shared.Screen.Print(StatisticsDump(false)); ResetStatistics(); } - - private void CalculateProfileResult() + + protected void CalculateProfileResult() { ProfileResult = currentContext.GetCodeFragment(0, currentContext.Program.Count - 1, true); // Prepend a header string consisting of the block of summary text: ProfileResult.Insert(0, StatisticsDump(true)); } + ~CPU() => Dispose(false); public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + protected virtual void Dispose(bool disposing) { while (contexts.Count > 0) { @@ -1644,9 +1650,9 @@ public void StopCompileStopwatch() compileWatch.Stop(); } - private class BootGlobalPath : InternalPath + protected class BootGlobalPath : InternalPath { - private string command; + protected string command; public BootGlobalPath(string command) : base() { @@ -1664,4 +1670,4 @@ public override string ToString() } } } -} \ No newline at end of file +} diff --git a/src/kOS.Safe/Execution/IStack.cs b/src/kOS.Safe/Execution/IStack.cs index 9b86c1785..65090e91d 100644 --- a/src/kOS.Safe/Execution/IStack.cs +++ b/src/kOS.Safe/Execution/IStack.cs @@ -1,10 +1,35 @@ -using System; +using System; using System.Collections.Generic; namespace kOS.Safe.Execution { public interface IStack { + /// + /// Current size of argument stack + /// + int ArgumentCount { get; } + /// + /// Current size of scope stack + /// + int ScopeCount { get; } + /// + /// All arguments on the stack (from top to bottom) + /// + IEnumerable Arguments { get; } + /// + /// All arguments on the stack from bottom to top + /// + IEnumerable ArgumentsFromBottom { get; } + /// + /// All scopes on the stack (from top to bottom) + /// + IEnumerable Scopes { get; } + /// + /// All scopes on the stack from bottom to top + /// + IEnumerable ScopesFromBottom { get; } + void PushArgument(object item); object PopArgument(); object PeekArgument(int digDepth); diff --git a/src/kOS.Safe/Execution/Stack.cs b/src/kOS.Safe/Execution/Stack.cs index ad8ef0b0c..c18f65223 100644 --- a/src/kOS.Safe/Execution/Stack.cs +++ b/src/kOS.Safe/Execution/Stack.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; using kOS.Safe.Utilities; @@ -41,6 +41,59 @@ public class Stack : IStack private int triggerContextCount = 0; + /// + /// Current size of argument stack + /// + public int ArgumentCount => argumentCount; + /// + /// Current size of scope stack + /// + public int ScopeCount => scopeCount; + /// + /// All arguments on the stack (from top to bottom) + /// + public IEnumerable Arguments + { + get + { + for (int i = argumentCount; i > 0;) + yield return argumentStack[--i]; + } + } + /// + /// All arguments on the stack from bottom to top + /// + public IEnumerable ArgumentsFromBottom + { + get + { + for (int i = 0; i < argumentCount;) + yield return argumentStack[i++]; + } + } + /// + /// All scopes on the stack (from top to bottom) + /// + public IEnumerable Scopes + { + get + { + for (int i = scopeCount; i > 0;) + yield return scopeStack[--i]; + } + } + /// + /// All scopes on the stack from bottom to top + /// + public IEnumerable ScopesFromBottom + { + get + { + for (int i = 0; i < scopeCount;) + yield return scopeStack[i++]; + } + } + /// /// Push to the argument stack. /// @@ -453,4 +506,4 @@ public bool HasTriggerContexts() return triggerContextCount > 0; } } -} \ No newline at end of file +} From 40daa29bde82808de7a4c698489b28e00d757571 Mon Sep 17 00:00:00 2001 From: firda-cze Date: Fri, 30 Mar 2018 15:24:54 +0200 Subject: [PATCH 4/5] boot from archive - fix #2259 --- src/kOS.Safe/Execution/CPU.cs | 37 ++++++++++----- .../Execution/YieldFinishedCompile.cs | 47 ++++++++----------- .../Execution/YieldFinishedCompileBoot.cs | 27 +++++++++++ ...or.cs => YieldFinishedThreadedDetector.cs} | 36 +++++++++----- src/kOS.Safe/kOS.Safe.csproj | 5 +- 5 files changed, 99 insertions(+), 53 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 03c123125..7dd4a6157 100644 --- a/src/kOS.Safe/Execution/CPU.cs +++ b/src/kOS.Safe/Execution/CPU.cs @@ -149,17 +149,7 @@ public void Boot() shared.Screen?.Print(" \n" + "Proceed.\n"); } - else if (!shared.Processor.CheckCanBoot()) - { - shared.Screen?.Print(string.Format( - " \n" + - "Could not boot from {0}\n" + - "Probably no connection to home\n" + - " \n" + - "Proceed.\n", - path)); - } - 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 @@ -202,9 +192,32 @@ public void Boot() }; YieldProgram(YieldFinishedCompile.RunScript(new BootGlobalPath(bootCommand), 1, bootCommand, bootContext, options)); - } } + else //shared.Processor.CheckCanBoot() returned false + { + shared.Screen?.Print(string.Format( + " \n" + + "Waiting 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)); + } } protected 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..b781c3dcd --- /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); + } +} 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..4b9c10448 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,9 @@ 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 +70,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 +96,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 +110,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 2bab71216..cbdc7591f 100644 --- a/src/kOS.Safe/kOS.Safe.csproj +++ b/src/kOS.Safe/kOS.Safe.csproj @@ -181,8 +181,9 @@ - + + @@ -316,4 +317,4 @@ --> - + \ No newline at end of file From 1abd632328b42fc8cc4a40b22debf272b1a900a1 Mon Sep 17 00:00:00 2001 From: firda-cze Date: Tue, 1 May 2018 13:51:44 +0200 Subject: [PATCH 5/5] doc for booting from archive --- doc/source/general/volumes.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/source/general/volumes.rst b/doc/source/general/volumes.rst index 1553e9c09..d41a28910 100644 --- a/doc/source/general/volumes.rst +++ b/doc/source/general/volumes.rst @@ -191,10 +191,11 @@ migration. As soon as you vessel leaves VAB/SPH and is being initialised on the launchpad (e.g. its status is PRELAUNCH) the assigned script will be copied to CPU's -local hard disk with the same name. If kOS is configured to start on the -archive, the file will not be copied locally automatically. This script will -be run as soon as CPU boots, e.g. as soon as you bring your CPU in physics -range or power on your CPU if it was turned off. You may get or set the name +local hard disk with the same name. This script will be run as soon as CPU boots, +e.g. as soon as you bring your CPU in physics range or power on your CPU +if it was turned off. If kOS is configured to start on the archive, +the file will not be copied locally automatically and booting will be delayed, +until connection to archive is established. You may get or set the name of the boot file using the :attr:`kOSProcessor:BOOTFILENAME` suffix. Important things to consider: