mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #23643 from smarterclayton/leak
Automatic merge from submit-queue interrupt package (attach and edit) could leak a goroutine
This commit is contained in:
commit
49dd31a9a8
@ -22,12 +22,19 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Handler guarantees execution of notifications after a critical section (the function passed
|
||||||
|
// to a Run method), even in the presence of process termination. It guarantees exactly once
|
||||||
|
// invocation of the provided notify functions.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
notify []func()
|
notify []func()
|
||||||
final func(os.Signal)
|
final func(os.Signal)
|
||||||
once sync.Once
|
once sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Chain creates a new handler that invokes all notify functions when the critical section exits
|
||||||
|
// and then invokes the optional handler's notifications. This allows critical sections to be
|
||||||
|
// nested without losing exactly once invocations. Notify functions can invoke any cleanup needed
|
||||||
|
// but should not exit (which is the responsibility of the parent handler).
|
||||||
func Chain(handler *Handler, notify ...func()) *Handler {
|
func Chain(handler *Handler, notify ...func()) *Handler {
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
return New(nil, notify...)
|
return New(nil, notify...)
|
||||||
@ -35,6 +42,10 @@ func Chain(handler *Handler, notify ...func()) *Handler {
|
|||||||
return New(handler.Signal, append(notify, handler.Close)...)
|
return New(handler.Signal, append(notify, handler.Close)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a new handler that guarantees all notify functions are run after the critical
|
||||||
|
// section exits (or is interrupted by the OS), then invokes the final handler. If no final
|
||||||
|
// handler is specified, the default final is `os.Exit(0)`. A handler can only be used for
|
||||||
|
// one critical section.
|
||||||
func New(final func(os.Signal), notify ...func()) *Handler {
|
func New(final func(os.Signal), notify ...func()) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
final: final,
|
final: final,
|
||||||
@ -42,6 +53,7 @@ func New(final func(os.Signal), notify ...func()) *Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close executes all the notification handlers if they have not yet been executed.
|
||||||
func (h *Handler) Close() {
|
func (h *Handler) Close() {
|
||||||
h.once.Do(func() {
|
h.once.Do(func() {
|
||||||
for _, fn := range h.notify {
|
for _, fn := range h.notify {
|
||||||
@ -50,6 +62,9 @@ func (h *Handler) Close() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signal is called when an os.Signal is received, and guarantees that all notifications
|
||||||
|
// are executed, then the final handler is executed. This function should only be called once
|
||||||
|
// per Handler instance.
|
||||||
func (h *Handler) Signal(s os.Signal) {
|
func (h *Handler) Signal(s os.Signal) {
|
||||||
h.once.Do(func() {
|
h.once.Do(func() {
|
||||||
for _, fn := range h.notify {
|
for _, fn := range h.notify {
|
||||||
@ -62,10 +77,16 @@ func (h *Handler) Signal(s os.Signal) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run ensures that any notifications are invoked after the provided fn exits (even if the
|
||||||
|
// process is interrupted by an OS termination signal). Notifications are only invoked once
|
||||||
|
// per Handler instance, so calling Run more than once will not behave as the user expects.
|
||||||
func (h *Handler) Run(fn func() error) error {
|
func (h *Handler) Run(fn func() error) error {
|
||||||
ch := make(chan os.Signal, 1)
|
ch := make(chan os.Signal, 1)
|
||||||
signal.Notify(ch, childSignals...)
|
signal.Notify(ch, childSignals...)
|
||||||
defer signal.Stop(ch)
|
defer func() {
|
||||||
|
signal.Stop(ch)
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
sig, ok := <-ch
|
sig, ok := <-ch
|
||||||
if !ok {
|
if !ok {
|
||||||
|
Loading…
Reference in New Issue
Block a user