experimental REPL interrupting

This commit is contained in:
dzaima 2022-06-03 15:28:44 +03:00
parent 47e4e68eee
commit 7a21f9ef73
3 changed files with 36 additions and 6 deletions

View File

@ -237,6 +237,7 @@ void cbqn_runLine0(char* ln, i64 read) {
void cbqn_runLine(char* ln, i64 len) { void cbqn_runLine(char* ln, i64 len) {
if(CATCH) { if(CATCH) {
cbqn_takeInterrupts(false);
fprintf(stderr, "Error: "); printErrMsg(thrownMsg); fputc('\n', stderr); fprintf(stderr, "Error: "); printErrMsg(thrownMsg); fputc('\n', stderr);
vm_pst(envCurr+1, envStart+envPrevHeight); vm_pst(envCurr+1, envStart+envPrevHeight);
freeThrown(); freeThrown();
@ -246,7 +247,9 @@ void cbqn_runLine(char* ln, i64 len) {
gc_maybeGC(); gc_maybeGC();
return; return;
} }
cbqn_takeInterrupts(true);
cbqn_runLine0(ln, len); cbqn_runLine0(ln, len);
cbqn_takeInterrupts(false);
popCatch(); popCatch();
} }

View File

@ -843,7 +843,35 @@ B mnvmExecBodyInline(Body* body, Scope* sc) {
#if __has_include(<signal.h>) && REPL_INTERRUPT
volatile int cbqn_interrupted;
#include <signal.h>
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 FORCE_INLINE B execBlock(Block* block, Body* body, Scope* psc, i32 ga, B* svar) { // consumes svar contents
CHECK_INTERRUPT;
u16 varAm = body->varAm; u16 varAm = body->varAm;
assert(varAm>=ga); assert(varAm>=ga);
assert(ga == blockGivenVars(block)); assert(ga == blockGivenVars(block));
@ -1261,9 +1289,7 @@ void profiler_sigHandler(int x) {
profiler_buf_c = bn; profiler_buf_c = bn;
} }
static bool setProfHandler(bool b) {
static bool setHandler(bool b) {
struct sigaction act = {}; struct sigaction act = {};
act.sa_handler = b? profiler_sigHandler : SIG_DFL; act.sa_handler = b? profiler_sigHandler : SIG_DFL;
if (sigaction(SIGALRM/*SIGPROF*/, &act, NULL)) { if (sigaction(SIGALRM/*SIGPROF*/, &act, NULL)) {
@ -1272,7 +1298,7 @@ static bool setHandler(bool b) {
} }
return true; return true;
} }
static bool setTimer(i64 us) { static bool setProfTimer(i64 us) {
struct itimerval timer; struct itimerval timer;
timer.it_value.tv_sec=0; timer.it_value.tv_sec=0;
timer.it_value.tv_usec=us; timer.it_value.tv_usec=us;
@ -1307,13 +1333,13 @@ bool profiler_active;
bool profiler_start(i64 hz) { bool profiler_start(i64 hz) {
i64 us = 999999/hz; i64 us = 999999/hz;
profiler_active = true; profiler_active = true;
return setHandler(true) && setTimer(us); return setProfHandler(true) && setProfTimer(us);
} }
bool profiler_stop() { bool profiler_stop() {
if (!profiler_active) return false; if (!profiler_active) return false;
profiler_active = 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"); 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);
} }

View File

@ -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 printErrMsg(B msg);
NOINLINE void unwindEnv(Env* envNew); // envNew==envStart-1 for emptying the env stack 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! 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); usz getPageSize(void);