1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Break big lock into some tiny locks

Don't involve code waiting for blocking channel in locked critical
section because it has potential risk of hanging forever.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
This commit is contained in:
Zhang Wei 2015-12-17 11:20:30 +08:00
parent 1105caa7f1
commit 1326f0cba5
3 changed files with 30 additions and 4 deletions

View file

@ -80,6 +80,7 @@ type containerMonitor struct {
// StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy // StartMonitor initializes a containerMonitor for this container with the provided supervisor and restart policy
// and starts the container's process. // and starts the container's process.
func (container *Container) StartMonitor(s supervisor, policy container.RestartPolicy) error { func (container *Container) StartMonitor(s supervisor, policy container.RestartPolicy) error {
container.Lock()
container.monitor = &containerMonitor{ container.monitor = &containerMonitor{
supervisor: s, supervisor: s,
container: container, container: container,
@ -88,6 +89,7 @@ func (container *Container) StartMonitor(s supervisor, policy container.RestartP
stopChan: make(chan struct{}), stopChan: make(chan struct{}),
startSignal: make(chan struct{}), startSignal: make(chan struct{}),
} }
container.Unlock()
return container.monitor.wait() return container.monitor.wait()
} }
@ -157,6 +159,8 @@ func (m *containerMonitor) start() error {
} }
m.Close() m.Close()
}() }()
m.container.Lock()
// reset stopped flag // reset stopped flag
if m.container.HasBeenManuallyStopped { if m.container.HasBeenManuallyStopped {
m.container.HasBeenManuallyStopped = false m.container.HasBeenManuallyStopped = false
@ -171,16 +175,20 @@ func (m *containerMonitor) start() error {
if err := m.supervisor.StartLogging(m.container); err != nil { if err := m.supervisor.StartLogging(m.container); err != nil {
m.resetContainer(false) m.resetContainer(false)
m.container.Unlock()
return err return err
} }
pipes := execdriver.NewPipes(m.container.Stdin(), m.container.Stdout(), m.container.Stderr(), m.container.Config.OpenStdin) pipes := execdriver.NewPipes(m.container.Stdin(), m.container.Stdout(), m.container.Stderr(), m.container.Config.OpenStdin)
m.container.Unlock()
m.logEvent("start") m.logEvent("start")
m.lastStartTime = time.Now() m.lastStartTime = time.Now()
// don't lock Run because m.callback has own lock
if exitStatus, err = m.supervisor.Run(m.container, pipes, m.callback); err != nil { if exitStatus, err = m.supervisor.Run(m.container, pipes, m.callback); err != nil {
m.container.Lock()
// if we receive an internal error from the initial start of a container then lets // if we receive an internal error from the initial start of a container then lets
// return it instead of entering the restart loop // return it instead of entering the restart loop
// set to 127 for container cmd not found/does not exist) // set to 127 for container cmd not found/does not exist)
@ -190,6 +198,7 @@ func (m *containerMonitor) start() error {
if m.container.RestartCount == 0 { if m.container.RestartCount == 0 {
m.container.ExitCode = 127 m.container.ExitCode = 127
m.resetContainer(false) m.resetContainer(false)
m.container.Unlock()
return derr.ErrorCodeCmdNotFound return derr.ErrorCodeCmdNotFound
} }
} }
@ -198,6 +207,7 @@ func (m *containerMonitor) start() error {
if m.container.RestartCount == 0 { if m.container.RestartCount == 0 {
m.container.ExitCode = 126 m.container.ExitCode = 126
m.resetContainer(false) m.resetContainer(false)
m.container.Unlock()
return derr.ErrorCodeCmdCouldNotBeInvoked return derr.ErrorCodeCmdCouldNotBeInvoked
} }
} }
@ -206,11 +216,13 @@ func (m *containerMonitor) start() error {
m.container.ExitCode = -1 m.container.ExitCode = -1
m.resetContainer(false) m.resetContainer(false)
m.container.Unlock()
return derr.ErrorCodeCantStart.WithArgs(m.container.ID, utils.GetErrorMessage(err)) return derr.ErrorCodeCantStart.WithArgs(m.container.ID, utils.GetErrorMessage(err))
} }
m.container.Unlock()
logrus.Errorf("Error running container: %s", err) logrus.Errorf("Error running container: %s", err)
} } // end if
// here container.Lock is already lost // here container.Lock is already lost
afterRun = true afterRun = true
@ -231,13 +243,14 @@ func (m *containerMonitor) start() error {
if m.shouldStop { if m.shouldStop {
return err return err
} }
m.container.Lock()
continue continue
} }
m.logEvent("die") m.logEvent("die")
m.resetContainer(true) m.resetContainer(true)
return err return err
} } // end for
} }
// resetMonitor resets the stateful fields on the containerMonitor based on the // resetMonitor resets the stateful fields on the containerMonitor based on the
@ -319,7 +332,7 @@ func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid
} }
} }
m.container.SetRunning(pid) m.container.SetRunningLocking(pid)
// signal that the process has started // signal that the process has started
// close channel only if not closed // close channel only if not closed

View file

@ -179,6 +179,13 @@ func (s *State) getExitCode() int {
return res return res
} }
// SetRunningLocking locks container and sets it to "running"
func (s *State) SetRunningLocking(pid int) {
s.Lock()
s.SetRunning(pid)
s.Unlock()
}
// SetRunning sets the state of the container to "running". // SetRunning sets the state of the container to "running".
func (s *State) SetRunning(pid int) { func (s *State) SetRunning(pid int) {
s.Error = "" s.Error = ""
@ -192,7 +199,7 @@ func (s *State) SetRunning(pid int) {
s.waitChan = make(chan struct{}) s.waitChan = make(chan struct{})
} }
// SetStoppedLocking locks the container state is sets it to "stopped". // SetStoppedLocking locks the container state and sets it to "stopped".
func (s *State) SetStoppedLocking(exitStatus *execdriver.ExitStatus) { func (s *State) SetStoppedLocking(exitStatus *execdriver.ExitStatus) {
s.Lock() s.Lock()
s.SetStopped(exitStatus) s.SetStopped(exitStatus)

View file

@ -129,9 +129,15 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
mounts = append(mounts, container.TmpfsMounts()...) mounts = append(mounts, container.TmpfsMounts()...)
container.Command.Mounts = mounts container.Command.Mounts = mounts
container.Unlock()
// don't lock waitForStart because it has potential risk of blocking
// which will lead to dead lock, forever.
if err := daemon.waitForStart(container); err != nil { if err := daemon.waitForStart(container); err != nil {
container.Lock()
return err return err
} }
container.Lock()
container.HasBeenStartedBefore = true container.HasBeenStartedBefore = true
return nil return nil
} }