1 /** 2 * Copyright: Enalye 3 * License: Zlib 4 * Authors: Enalye 5 */ 6 module grimoire.runtime.sandbox; 7 8 import std.stdio, core.thread; 9 import grimoire; 10 11 /// Handle a grimoire VM safely. 12 final class GrSandbox { 13 private final class TimeoutThread: Thread { 14 private { 15 __gshared GrSandbox _script; 16 } 17 shared bool isRunning = true; 18 shared bool isTimedout; 19 20 this(GrSandbox script) { 21 _script = script; 22 super(&run); 23 } 24 25 void run() { 26 try { 27 const auto startTime = MonoTime.currTime(); 28 while(isRunning) { 29 const auto currentCycle = _script._cycle; 30 sleep(dur!("msecs")(100)); 31 if(currentCycle == _script._cycle && _script._isLoaded) { 32 isTimedout = true; 33 isRunning = false; 34 _script.engine.isRunning = false; 35 } 36 const auto deltaTime = MonoTime.currTime() - startTime; 37 if(deltaTime > dur!"msecs"(1000)) { 38 isTimedout = true; 39 isRunning = false; 40 _script.engine.isRunning = false; 41 } 42 } 43 } 44 catch(Exception e) { 45 writeln("Script timeout error: ", e.msg); 46 } 47 } 48 } 49 50 private { 51 shared int _cycle; 52 shared bool _isLoaded = false; 53 TimeoutThread _timeout; 54 } 55 56 GrEngine engine; 57 58 @property { 59 bool isRunning() { return engine.hasCoroutines && !engine.isPanicking && engine.isRunning; } 60 bool isTimedout() { return _timeout.isTimedout; } 61 } 62 63 void cleanup() { 64 engine.isRunning = false; 65 _isLoaded = false; 66 if(_timeout) { 67 _timeout.isRunning = false; 68 _timeout = null; 69 } 70 } 71 72 /*void load(string name) { 73 auto bytecode = grCompileFile(name); 74 engine = new GrEngine; 75 engine.load(bytecode); 76 engine.spawn(); 77 _timeout = new TimeoutThread(this); 78 _timeout.start(); 79 }*/ 80 81 void run() { 82 _isLoaded = true; 83 if(engine.hasCoroutines) 84 engine.process(); 85 _cycle = _cycle + 1; 86 if(!engine.hasCoroutines || engine.isPanicking) 87 _timeout.isRunning = false; 88 } 89 }