X-Git-Url: https://git.korewanetadesu.com/?p=go-signalcontext.git;a=blobdiff_plain;f=context.go;h=5ed10d592ed02faa4f4d99284a86a14c31a764be;hp=1bd24d317d105d42a87fa8e043ae677540631e92;hb=HEAD;hpb=8cf685c73e37c718d1dcfe057caad080196f3e18 diff --git a/context.go b/context.go index 1bd24d3..5ed10d5 100644 --- a/context.go +++ b/context.go @@ -9,7 +9,8 @@ import ( ) // A Context is an implementation of the context.Context interface which -// completes when a signal (e.g. os.Interrupt) is received. +// cancels when an operating system signal (e.g. os.Interrupt) is +// received. // // Contexts should be created via the UntilSignal function. type Context struct { @@ -23,19 +24,20 @@ type Context struct { c chan os.Signal } -// UntilSignal returns a new Context which will complete when the parent -// does or when any of the specified signals are received. +// UntilSignal returns a new Context which will cancel when the parent +// does or when any of the specified operating system signals are +// received. func UntilSignal(parent context.Context, sig ...os.Signal) *Context { ctx := new(Context) ctx.parent = parent - ctx.done = make(chan struct{}) if err := parent.Err(); err != nil { - close(ctx.done) + ctx.done = alreadyclosed ctx.err = err return ctx } + ctx.done = make(chan struct{}) ctx.c = make(chan os.Signal, 1) signal.Notify(ctx.c, sig...) go ctx.wait(sig...) @@ -63,8 +65,10 @@ func (s *Context) wait(sig ...os.Signal) { close(s.done) } -// Cancel cancels this context, if it hasn’t already been completed. (If -// it has, this is safe but has no effect.) +// Cancel cancels this context, if it hasn’t already been. (If it has, +// this is safe but has no effect.) Canceling this context releases +// resources associated with it and stops listening for the configured +// operating system signals. func (s *Context) Cancel() { s.m.Lock() if s.c != nil { @@ -83,23 +87,35 @@ func (s *Context) Deadline() (time.Time, bool) { return s.parent.Deadline() } -// Value implements context.Context; any value is that of its parent. +// Value implements context.Context; any Context value is that of its +// parent. func (s *Context) Value(key interface{}) interface{} { return s.parent.Value(key) } -// Done implements context.Context. +// Done returns a channel that's closed when work done on behalf of this +// context should be canceled, either because the parent finished or +// because one of the configured operating system signals was received. func (s *Context) Done() <-chan struct{} { return s.done } // Err implements context.Context; it returns context.Canceled if the -// context was canceled; an Error if the context completed due to a -// signal; the parent’s error if the parent was done before either of -// those; or nil if the context is not yet done. +// context was canceled by its Cancel method; an Error if the context +// canceled due to a operating system signal; the parent’s error if the +// parent canceled before either of those; or nil if the context is not +// yet canceled. func (s *Context) Err() error { s.m.Lock() err := s.err s.m.Unlock() return err } + +// Reuse the same channel for all Contexts which begin life already +// canceled. +var alreadyclosed = make(chan struct{}) + +func init() { + close(alreadyclosed) +}