12 // A SignalContext is an implementation of the context.Context interface
13 // which completes when a signal (e.g. os.Interrupt) is received.
15 // SignalContexts should be created via the UntilSignal function.
16 type SignalContext struct {
17 parent context.Context
21 // The mutex synchronizes access to err and clearing the
22 // internal Signal channel after initialization.
27 // UntilSignal returns a new SignalContext which will complete when the
28 // parent does or when any of the specified signals are received.
29 func UntilSignal(parent context.Context, sig ...os.Signal) *SignalContext {
30 ctx := new(SignalContext)
32 ctx.done = make(chan struct{})
34 if err := parent.Err(); err != nil {
40 ctx.c = make(chan os.Signal, 1)
41 signal.Notify(ctx.c, sig...)
46 func (s *SignalContext) wait(sig ...os.Signal) {
49 case <-s.parent.Done():
67 // Cancel cancels this context, if it hasn’t already been canceled or
68 // received a signal. (If it has, this is safe but has no effect.)
69 func (s *SignalContext) Cancel() {
72 s.err = context.Canceled
81 // Deadline implements context.Context; a SignalContext’s deadline is
82 // that of its parent.
83 func (s *SignalContext) Deadline() (time.Time, bool) {
84 return s.parent.Deadline()
87 // Value implements context.Context; any value is that of its parent.
88 func (s *SignalContext) Value(key interface{}) interface{} {
89 return s.parent.Value(key)
92 // Done implements context.Context.
93 func (s *SignalContext) Done() <-chan struct{} {
97 // Err implements context.Context; it returns context.Canceled if the
98 // context was canceled; a SignalError if the context completed due to a
99 // signal; the parent’s error if the parent was done before either of
100 // those; or nil if the context is not yet done.
101 func (s *SignalContext) Err() error {
108 // A SignalError will be returned by a SignalContext’s Err() method when
109 // it was finished due to a signal (rather than e.g. parent
111 type SignalError struct {
115 func (e SignalError) Error() string {
119 func (e SignalError) String() string {
120 return fmt.Sprintf("received signal: %s", e.Signal)