From 7a21f9ef73a0686104b309e637879c76de1414be Mon Sep 17 00:00:00 2001 From: dzaima Date: Fri, 3 Jun 2022 15:28:44 +0300 Subject: [PATCH] experimental REPL interrupting --- src/main.c | 3 +++ src/vm.c | 38 ++++++++++++++++++++++++++++++++------ src/vm.h | 1 + 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index 323d7cfc..d234164c 100644 --- a/src/main.c +++ b/src/main.c @@ -237,6 +237,7 @@ void cbqn_runLine0(char* ln, i64 read) { void cbqn_runLine(char* ln, i64 len) { if(CATCH) { + cbqn_takeInterrupts(false); fprintf(stderr, "Error: "); printErrMsg(thrownMsg); fputc('\n', stderr); vm_pst(envCurr+1, envStart+envPrevHeight); freeThrown(); @@ -246,7 +247,9 @@ void cbqn_runLine(char* ln, i64 len) { gc_maybeGC(); return; } + cbqn_takeInterrupts(true); cbqn_runLine0(ln, len); + cbqn_takeInterrupts(false); popCatch(); } diff --git a/src/vm.c b/src/vm.c index 374ee3e6..feb59bb6 100644 --- a/src/vm.c +++ b/src/vm.c @@ -843,7 +843,35 @@ B mnvmExecBodyInline(Body* body, Scope* sc) { +#if __has_include() && REPL_INTERRUPT +volatile int cbqn_interrupted; +#include +bool cbqn_takeInterrupts(bool b); +static void interrupt_sigHandler(int x) { + if (cbqn_interrupted) abort(); // shouldn't happen + cbqn_takeInterrupts(false); + cbqn_interrupted = 1; +} +bool cbqn_takeInterrupts(bool b) { // returns if succeeded + if (!b) cbqn_interrupted = 0; // can be left dangling if nothing caught it + struct sigaction act = {}; + act.sa_handler = b? interrupt_sigHandler : SIG_DFL; + return sigaction(SIGINT, &act, NULL) == 0; +} + +NOINLINE NORETURN void cbqn_onInterrupt() { + cbqn_interrupted = 0; + thrM("interrupted"); +} +#define CHECK_INTERRUPT ({ if (cbqn_interrupted) cbqn_onInterrupt(); }) +#else +bool cbqn_takeInterrupts(bool b) { return false; } +#define CHECK_INTERRUPT +#endif + + FORCE_INLINE B execBlock(Block* block, Body* body, Scope* psc, i32 ga, B* svar) { // consumes svar contents + CHECK_INTERRUPT; u16 varAm = body->varAm; assert(varAm>=ga); assert(ga == blockGivenVars(block)); @@ -1261,9 +1289,7 @@ void profiler_sigHandler(int x) { profiler_buf_c = bn; } - - -static bool setHandler(bool b) { +static bool setProfHandler(bool b) { struct sigaction act = {}; act.sa_handler = b? profiler_sigHandler : SIG_DFL; if (sigaction(SIGALRM/*SIGPROF*/, &act, NULL)) { @@ -1272,7 +1298,7 @@ static bool setHandler(bool b) { } return true; } -static bool setTimer(i64 us) { +static bool setProfTimer(i64 us) { struct itimerval timer; timer.it_value.tv_sec=0; timer.it_value.tv_usec=us; @@ -1307,13 +1333,13 @@ bool profiler_active; bool profiler_start(i64 hz) { i64 us = 999999/hz; profiler_active = true; - return setHandler(true) && setTimer(us); + return setProfHandler(true) && setProfTimer(us); } bool profiler_stop() { if (!profiler_active) return false; profiler_active = false; if (profile_buf_full) fprintf(stderr, "Profiler buffer ran out in the middle of execution. Only timings of the start of profiling will be shown.\n"); - return setTimer(0) && setHandler(false); + return setProfTimer(0) && setProfHandler(false); } diff --git a/src/vm.h b/src/vm.h index 1f84d51f..26eb979c 100644 --- a/src/vm.h +++ b/src/vm.h @@ -236,6 +236,7 @@ NOINLINE B vm_fmtPoint(B src, B prepend, B path, usz cs, usz ce); // consumes pr NOINLINE void printErrMsg(B msg); NOINLINE void unwindEnv(Env* envNew); // envNew==envStart-1 for emptying the env stack NOINLINE void unwindCompiler(void); // unwind to the env of the invocation of the compiler; UB when not in compiler! +bool cbqn_takeInterrupts(bool b); usz getPageSize(void);