diff --git a/daemon/daemon.go b/daemon/daemon.go index ec9a759f77..8bcb3f07a4 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -830,6 +830,45 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo return d, nil } +func stopContainer(c *Container) error { + // TODO(windows): Handle docker restart with paused containers + if c.isPaused() { + // To terminate a process in freezer cgroup, we should send + // SIGTERM to this process then unfreeze it, and the process will + // force to terminate immediately. + logrus.Debugf("Found container %s is paused, sending SIGTERM before unpause it", c.ID) + sig, ok := signal.SignalMap["TERM"] + if !ok { + return fmt.Errorf("System doesn not support SIGTERM") + } + if err := c.daemon.kill(c, int(sig)); err != nil { + return fmt.Errorf("sending SIGTERM to container %s with error: %v", c.ID, err) + } + if err := c.unpause(); err != nil { + return fmt.Errorf("Failed to unpause container %s with error: %v", c.ID, err) + } + if _, err := c.WaitStop(10 * time.Second); err != nil { + logrus.Debugf("container %s failed to exit in 10 second of SIGTERM, sending SIGKILL to force", c.ID) + sig, ok := signal.SignalMap["KILL"] + if !ok { + return fmt.Errorf("System does not support SIGKILL") + } + if err := c.daemon.kill(c, int(sig)); err != nil { + logrus.Errorf("Failed to SIGKILL container %s", c.ID) + } + c.WaitStop(-1 * time.Second) + return err + } + } + // If container failed to exit in 10 seconds of SIGTERM, then using the force + if err := c.Stop(10); err != nil { + return fmt.Errorf("Stop container %s with error: %v", c.ID, err) + } + + c.WaitStop(-1 * time.Second) + return nil +} + // Shutdown stops the daemon. func (daemon *Daemon) Shutdown() error { daemon.shutdown = true @@ -837,58 +876,26 @@ func (daemon *Daemon) Shutdown() error { group := sync.WaitGroup{} logrus.Debug("starting clean shutdown of all containers...") for _, container := range daemon.List() { - c := container - if c.IsRunning() { - logrus.Debugf("stopping %s", c.ID) - group.Add(1) - - go func() { - defer group.Done() - // TODO(windows): Handle docker restart with paused containers - if c.isPaused() { - // To terminate a process in freezer cgroup, we should send - // SIGTERM to this process then unfreeze it, and the process will - // force to terminate immediately. - logrus.Debugf("Found container %s is paused, sending SIGTERM before unpause it", c.ID) - sig, ok := signal.SignalMap["TERM"] - if !ok { - logrus.Warnf("System does not support SIGTERM") - return - } - if err := daemon.kill(c, int(sig)); err != nil { - logrus.Debugf("sending SIGTERM to container %s with error: %v", c.ID, err) - return - } - if err := c.unpause(); err != nil { - logrus.Debugf("Failed to unpause container %s with error: %v", c.ID, err) - return - } - if _, err := c.WaitStop(10 * time.Second); err != nil { - logrus.Debugf("container %s failed to exit in 10 second of SIGTERM, sending SIGKILL to force", c.ID) - sig, ok := signal.SignalMap["KILL"] - if !ok { - logrus.Warnf("System does not support SIGKILL") - return - } - daemon.kill(c, int(sig)) - } - } else { - // If container failed to exit in 10 seconds of SIGTERM, then using the force - if err := c.Stop(10); err != nil { - logrus.Errorf("Stop container %s with error: %v", c.ID, err) - } - } - c.WaitStop(-1 * time.Second) - logrus.Debugf("container stopped %s", c.ID) - }() + if !container.IsRunning() { + continue } + logrus.Debugf("stopping %s", container.ID) + group.Add(1) + go func(c *Container) { + defer group.Done() + if err := stopContainer(c); err != nil { + logrus.Errorf("Stop container error: %v", err) + return + } + logrus.Debugf("container stopped %s", c.ID) + }(container) } group.Wait() + } - // trigger libnetwork Stop only if it's initialized - if daemon.netController != nil { - daemon.netController.Stop() - } + // trigger libnetwork Stop only if it's initialized + if daemon.netController != nil { + daemon.netController.Stop() } if daemon.containerGraphDB != nil {