From 940dc16bb1952d7f8dba4d1e2a71c45e4f903b15 Mon Sep 17 00:00:00 2001 From: Qi Xiao Date: Mon, 22 Feb 2016 17:39:03 +0100 Subject: [PATCH] Try to respond to signals sent to elvish-stub. Doesn't always work, but the behavior is consistent in a session (if it works, then it works in this session; vice versa). Likely some race in startup code. --- eval/builtin_func.go | 8 +++++++- eval/eval.go | 32 +++++++++++++++++++++++++++++++- stub/stub.go | 6 +++--- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/eval/builtin_func.go b/eval/builtin_func.go index ac291f74..69a67a39 100644 --- a/eval/builtin_func.go +++ b/eval/builtin_func.go @@ -109,6 +109,7 @@ var ( ErrStoreNotConnected = errors.New("store not connected") ErrNoMatchingDir = errors.New("no matching directory") ErrNotInSameGroup = errors.New("not in the same process group") + ErrInterrupted = errors.New("interrupted") ) var ( @@ -638,7 +639,12 @@ func fg(ec *EvalCtx, pids ...int) { } func _sleep(ec *EvalCtx, t float64) { - time.Sleep(time.Duration(t) * time.Second) + d := time.Duration(float64(time.Second) * t) + select { + case <-ec.intCh: + throw(ErrInterrupted) + case <-time.After(d): + } } func _stack(ec *EvalCtx) { diff --git a/eval/eval.go b/eval/eval.go index efc03cc1..93cb5f46 100644 --- a/eval/eval.go +++ b/eval/eval.go @@ -36,6 +36,7 @@ type Evaler struct { modules map[string]Namespace store *store.Store Stub *stub.Stub + intCh <-chan struct{} } // EvalCtx maintains an Evaler along with its runtime context. After creation @@ -56,7 +57,7 @@ func (ec *EvalCtx) evaling(n parse.Node) { // NewEvaler creates a new Evaler. func NewEvaler(st *store.Store) *Evaler { - ev := &Evaler{nil, map[string]Namespace{}, st, nil} + ev := &Evaler{nil, map[string]Namespace{}, st, nil, nil} // Construct initial global namespace pid := String(strconv.Itoa(syscall.Getpid())) @@ -180,6 +181,35 @@ func (ev *Evaler) EvalInteractive(text string, n *parse.Chunk) error { if err != nil { fmt.Println("failed to put stub in foreground:", err) } + + intCh := make(chan struct{}) + cancelCh := make(chan struct{}) + exhaustSigs: + for { + select { + case <-ev.Stub.Signals(): + default: + break exhaustSigs + } + } + go func() { + sigch := ev.Stub.Signals() + for { + select { + case sig := <-sigch: + fmt.Println(sig) + if sig == syscall.SIGINT { + close(intCh) + return + } + case <-cancelCh: + return + } + } + }() + defer close(cancelCh) + ev.intCh = intCh + defer func() { ev.intCh = nil }() } err := ev.Eval("[interactive]", text, n, ports) diff --git a/stub/stub.go b/stub/stub.go index 7e874648..50d5203a 100644 --- a/stub/stub.go +++ b/stub/stub.go @@ -116,10 +116,10 @@ func relaySignals(reader io.Reader, sigch chan<- os.Signal) { var signum int _, err := fmt.Fscanf(reader, "%d", &signum) if err != nil { - // XXX Swallow error. - return + sigch <- BadSignal{err} + } else { + sigch <- syscall.Signal(signum) } - sigch <- syscall.Signal(signum) } }