2017-07-07 05:18:26 +08:00
|
|
|
package eval
|
|
|
|
|
2018-10-12 13:44:40 +08:00
|
|
|
import (
|
2023-05-08 04:44:28 +08:00
|
|
|
"context"
|
2018-10-12 13:44:40 +08:00
|
|
|
"errors"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"syscall"
|
|
|
|
)
|
2017-07-07 05:18:26 +08:00
|
|
|
|
2023-05-08 04:44:28 +08:00
|
|
|
// ErrInterrupted is thrown when the execution is interrupted by a signal.
|
|
|
|
var ErrInterrupted = errors.New("interrupted")
|
|
|
|
|
|
|
|
// Used to "cancel" a finished evaluation. It is a bug if this actually cancels
|
|
|
|
// anything.
|
|
|
|
var errEvalFinished = errors.New("internal bug, eval should have finished")
|
|
|
|
|
|
|
|
// ListenInterrupts returns a Context that is canceled when SIGINT or SIGQUIT
|
|
|
|
// has been received by the process. It also returns a function to cancel the
|
|
|
|
// Context, which should be called when it is no longer needed.
|
|
|
|
func ListenInterrupts() (context.Context, func()) {
|
2023-05-08 04:49:27 +08:00
|
|
|
ctx, cancel := context.WithCancelCause(context.Background())
|
|
|
|
|
2021-08-23 07:22:11 +08:00
|
|
|
sigCh := make(chan os.Signal, 1)
|
2018-10-12 13:44:40 +08:00
|
|
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGQUIT)
|
|
|
|
|
|
|
|
go func() {
|
2023-05-08 04:44:28 +08:00
|
|
|
select {
|
|
|
|
case <-sigCh:
|
|
|
|
cancel(ErrInterrupted)
|
|
|
|
case <-ctx.Done():
|
2018-10-12 13:44:40 +08:00
|
|
|
}
|
|
|
|
signal.Stop(sigCh)
|
|
|
|
}()
|
|
|
|
|
2023-05-08 04:44:28 +08:00
|
|
|
return ctx, func() {
|
|
|
|
cancel(errEvalFinished)
|
2018-10-12 13:44:40 +08:00
|
|
|
}
|
|
|
|
}
|