protected override IConsole CreateConsole(ScriptEngine engine, CommandLine commandLine, ConsoleOptions options) { IConsole console = base.CreateConsole(engine, commandLine, options); Thread mainThread = Thread.CurrentThread; RubyContext context = (RubyContext)HostingHelpers.GetLanguageContext(engine); context.InterruptSignalHandler = delegate() { RubyUtils.RaiseAsyncException(mainThread, new Interrupt()); }; ((BasicConsole)console).ConsoleCancelEventHandler = delegate(object sender, ConsoleCancelEventArgs e) { OnCancelKey(sender, e, context, mainThread); }; return(console); }
private static void OnCancelKey(object sender, ConsoleCancelEventArgs ev, RubyContext context, Thread mainThread) { if (ev.SpecialKey == ConsoleSpecialKey.ControlC) { ev.Cancel = true; Action handler = context.InterruptSignalHandler; if (handler != null) { try { handler(); } catch (Exception e) { RubyUtils.RaiseAsyncException(mainThread, e); } } } }
private static void RaiseAsyncException(Thread thread, Exception exception) { RubyThreadStatus status = GetStatus(thread); // rethrow semantics, preserves the backtrace associated with the exception: RubyUtils.RaiseAsyncException(thread, exception); if (status == RubyThreadStatus.Sleeping) { // Thread.Abort can interrupt a thread with ThreadState.WaitSleepJoin. However, Thread.Abort // is deferred while the thread is in a catch block. If there is a Kernel.sleep in a catch block, // then that sleep will not be interrupted. // TODO: We should call Run to nudge the thread if its CurrentException is not-null, and // ThreadOps.Stop should have a checkpoint to see whether an async exception needs to be thrown // Run(thread); } }