github.com/portworx/docker@v1.12.1/daemon/stop.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/container" 10 "github.com/docker/docker/errors" 11 ) 12 13 // ContainerStop looks for the given container and terminates it, 14 // waiting the given number of seconds before forcefully killing the 15 // container. If a negative number of seconds is given, ContainerStop 16 // will wait for a graceful termination. An error is returned if the 17 // container is not found, is already stopped, or if there is a 18 // problem stopping the container. 19 func (daemon *Daemon) ContainerStop(name string, seconds int) error { 20 container, err := daemon.GetContainer(name) 21 if err != nil { 22 return err 23 } 24 if !container.IsRunning() { 25 err := fmt.Errorf("Container %s is already stopped", name) 26 return errors.NewErrorWithStatusCode(err, http.StatusNotModified) 27 } 28 if err := daemon.containerStop(container, seconds); err != nil { 29 return fmt.Errorf("Cannot stop container %s: %v", name, err) 30 } 31 return nil 32 } 33 34 // containerStop halts a container by sending a stop signal, waiting for the given 35 // duration in seconds, and then calling SIGKILL and waiting for the 36 // process to exit. If a negative duration is given, Stop will wait 37 // for the initial signal forever. If the container is not running Stop returns 38 // immediately. 39 func (daemon *Daemon) containerStop(container *container.Container, seconds int) error { 40 if !container.IsRunning() { 41 return nil 42 } 43 44 daemon.stopHealthchecks(container) 45 46 stopSignal := container.StopSignal() 47 // 1. Send a stop signal 48 if err := daemon.killPossiblyDeadProcess(container, stopSignal); err != nil { 49 logrus.Infof("Failed to send signal %d to the process, force killing", stopSignal) 50 if err := daemon.killPossiblyDeadProcess(container, 9); err != nil { 51 return err 52 } 53 } 54 55 // 2. Wait for the process to exit on its own 56 if _, err := container.WaitStop(time.Duration(seconds) * time.Second); err != nil { 57 logrus.Infof("Container %v failed to exit within %d seconds of signal %d - using the force", container.ID, seconds, stopSignal) 58 // 3. If it doesn't, then send SIGKILL 59 if err := daemon.Kill(container); err != nil { 60 container.WaitStop(-1 * time.Second) 61 logrus.Warn(err) // Don't return error because we only care that container is stopped, not what function stopped it 62 } 63 } 64 65 daemon.LogContainerEvent(container, "stop") 66 return nil 67 }