Skip to content

Commit

Permalink
Ensure shutdown handler access is syncronized
Browse files Browse the repository at this point in the history
There was a potential race where two handlers could be added at
the same time. Go Maps are not thread-safe, so that could do
unpleasant things. Add a mutex to keep things safe.

Also, swap the order or Register and Start for the handlers in
Libpod runtime created. As written, there was a small gap between
Start and Register where SIGTERM/SIGINT would be completely
ignored, instead of stopping Podman. Swapping the two closes this
gap.

Signed-off-by: Matthew Heon <[email protected]>
  • Loading branch information
mheon committed Jan 29, 2021
1 parent c48753b commit 07f2df4
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 11 deletions.
14 changes: 7 additions & 7 deletions libpod/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R
}
}

if err := shutdown.Register("libpod", func(sig os.Signal) error {
os.Exit(1)
return nil
}); err != nil && errors.Cause(err) != shutdown.ErrHandlerExists {
logrus.Errorf("Error registering shutdown handler for libpod: %v", err)
}

if err := shutdown.Start(); err != nil {
return nil, errors.Wrapf(err, "error starting shutdown signal handler")
}
Expand All @@ -188,13 +195,6 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R
return nil, err
}

if err := shutdown.Register("libpod", func(sig os.Signal) error {
os.Exit(1)
return nil
}); err != nil && errors.Cause(err) != shutdown.ErrHandlerExists {
logrus.Errorf("Error registering shutdown handler for libpod: %v", err)
}

return runtime, nil
}

Expand Down
10 changes: 10 additions & 0 deletions libpod/shutdown/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ var (
stopped bool
sigChan chan os.Signal
cancelChan chan bool
// Syncronize accesses to the map
handlerLock sync.Mutex
// Definitions of all on-shutdown handlers
handlers map[string]func(os.Signal) error
// Ordering that on-shutdown handlers will be invoked.
Expand Down Expand Up @@ -50,6 +52,7 @@ func Start() error {
case sig := <-sigChan:
logrus.Infof("Received shutdown signal %v, terminating!", sig)
shutdownInhibit.Lock()
handlerLock.Lock()
for _, name := range handlerOrder {
handler, ok := handlers[name]
if !ok {
Expand All @@ -61,6 +64,7 @@ func Start() error {
logrus.Errorf("Error running shutdown handler %s: %v", name, err)
}
}
handlerLock.Unlock()
shutdownInhibit.Unlock()
return
}
Expand Down Expand Up @@ -97,6 +101,9 @@ func Uninhibit() {
// by a signal. Handlers are invoked LIFO - the last handler registered is the
// first run.
func Register(name string, handler func(os.Signal) error) error {
handlerLock.Lock()
defer handlerLock.Unlock()

if handlers == nil {
handlers = make(map[string]func(os.Signal) error)
}
Expand All @@ -113,6 +120,9 @@ func Register(name string, handler func(os.Signal) error) error {

// Unregister un-registers a given shutdown handler.
func Unregister(name string) error {
handlerLock.Lock()
defer handlerLock.Unlock()

if handlers == nil {
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/api/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,15 @@ func setupSystemd() {
func (s *APIServer) Serve() error {
setupSystemd()

// Start the shutdown signal handler.
if err := shutdown.Start(); err != nil {
return err
}
if err := shutdown.Register("server", func(sig os.Signal) error {
return s.Shutdown()
}); err != nil {
return err
}
// Start the shutdown signal handler.
if err := shutdown.Start(); err != nil {
return err
}

errChan := make(chan error, 1)

Expand Down

0 comments on commit 07f2df4

Please sign in to comment.