cmd/geth, console: support interrupting the js console (#23387)

Previously, Ctrl-C (SIGINT) was ignored during JS execution, so it was not
possible to get out of infinite loops in the console. With this change,
Ctrl-C now interrupts JS.

Fixes #23344

Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Martin Holst Swende
2021-12-11 16:51:05 +01:00
committed by GitHub
parent ae8ff2661d
commit 72c2c0ae7e
5 changed files with 193 additions and 63 deletions

View File

@ -20,6 +20,7 @@ package jsre
import (
crand "crypto/rand"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
@ -220,19 +221,33 @@ loop:
}
// Do executes the given function on the JS event loop.
// When the runtime is stopped, fn will not execute.
func (re *JSRE) Do(fn func(*goja.Runtime)) {
done := make(chan bool)
req := &evalReq{fn, done}
re.evalQueue <- req
<-done
select {
case re.evalQueue <- req:
<-done
case <-re.closed:
}
}
// stops the event loop before exit, optionally waits for all timers to expire
// Stop terminates the event loop, optionally waiting for all timers to expire.
func (re *JSRE) Stop(waitForCallbacks bool) {
select {
case <-re.closed:
case re.stopEventLoop <- waitForCallbacks:
<-re.closed
timeout := time.NewTimer(10 * time.Millisecond)
defer timeout.Stop()
for {
select {
case <-re.closed:
return
case re.stopEventLoop <- waitForCallbacks:
<-re.closed
return
case <-timeout.C:
// JS is blocked, interrupt and try again.
re.vm.Interrupt(errors.New("JS runtime stopped"))
}
}
}
@ -282,6 +297,19 @@ func (re *JSRE) Evaluate(code string, w io.Writer) {
})
}
// Interrupt stops the current JS evaluation.
func (re *JSRE) Interrupt(v interface{}) {
done := make(chan bool)
noop := func(*goja.Runtime) {}
select {
case re.evalQueue <- &evalReq{noop, done}:
// event loop is not blocked.
default:
re.vm.Interrupt(v)
}
}
// Compile compiles and then runs a piece of JS code.
func (re *JSRE) Compile(filename string, src string) (err error) {
re.Do(func(vm *goja.Runtime) { _, err = compileAndRun(vm, filename, src) })