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:
committed by
GitHub
parent
ae8ff2661d
commit
72c2c0ae7e
@ -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) })
|
||||
|
Reference in New Issue
Block a user