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

Merge pull request #7775 from LK4D4/merge_state_lock

Merge Container and State mutexes
This commit is contained in:
Victor Vieux 2014-08-29 11:25:21 -07:00
commit 280b64bc7b
4 changed files with 47 additions and 50 deletions

View file

@ -10,7 +10,6 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"syscall" "syscall"
"time" "time"
@ -43,7 +42,7 @@ var (
) )
type Container struct { type Container struct {
sync.Mutex *State
root string // Path to the "home" of the container, including metadata. root string // Path to the "home" of the container, including metadata.
basefs string // Path to the graphdriver mountpoint basefs string // Path to the graphdriver mountpoint
@ -55,7 +54,6 @@ type Container struct {
Args []string Args []string
Config *runconfig.Config Config *runconfig.Config
State *State
Image string Image string
NetworkSettings *NetworkSettings NetworkSettings *NetworkSettings
@ -276,7 +274,7 @@ func (container *Container) Start() (err error) {
container.Lock() container.Lock()
defer container.Unlock() defer container.Unlock()
if container.State.IsRunning() { if container.State.Running {
return nil return nil
} }
@ -526,11 +524,11 @@ func (container *Container) KillSig(sig int) error {
defer container.Unlock() defer container.Unlock()
// We could unpause the container for them rather than returning this error // We could unpause the container for them rather than returning this error
if container.State.IsPaused() { if container.State.Paused {
return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID) return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID)
} }
if !container.State.IsRunning() { if !container.State.Running {
return nil return nil
} }
@ -541,7 +539,7 @@ func (container *Container) KillSig(sig int) error {
// if the container is currently restarting we do not need to send the signal // if the container is currently restarting we do not need to send the signal
// to the process. Telling the monitor that it should exit on it's next event // to the process. Telling the monitor that it should exit on it's next event
// loop is enough // loop is enough
if container.State.IsRestarting() { if container.State.Restarting {
return nil return nil
} }

View file

@ -70,7 +70,7 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
writeCont := func(container *Container) error { writeCont := func(container *Container) error {
container.Lock() container.Lock()
defer container.Unlock() defer container.Unlock()
if !container.State.IsRunning() && !all && n <= 0 && since == "" && before == "" { if !container.State.Running && !all && n <= 0 && since == "" && before == "" {
return nil return nil
} }
if before != "" && !foundBefore { if before != "" && !foundBefore {
@ -87,7 +87,7 @@ func (daemon *Daemon) Containers(job *engine.Job) engine.Status {
return errLast return errLast
} }
} }
if len(filt_exited) > 0 && !container.State.IsRunning() { if len(filt_exited) > 0 && !container.State.Running {
should_skip := true should_skip := true
for _, code := range filt_exited { for _, code := range filt_exited {
if code == container.State.GetExitCode() { if code == container.State.GetExitCode() {

View file

@ -110,7 +110,7 @@ func (m *containerMonitor) Start() error {
defer func() { defer func() {
if afterRun { if afterRun {
m.container.Lock() m.container.Lock()
m.container.State.SetStopped(exitStatus) m.container.State.setStopped(exitStatus)
defer m.container.Unlock() defer m.container.Unlock()
} }
m.Close() m.Close()
@ -123,7 +123,7 @@ func (m *containerMonitor) Start() error {
m.container.RestartCount++ m.container.RestartCount++
if err := m.container.startLoggingToDisk(); err != nil { if err := m.container.startLoggingToDisk(); err != nil {
m.resetContainer() m.resetContainer(false)
return err return err
} }
@ -138,7 +138,7 @@ func (m *containerMonitor) Start() error {
// 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
if m.container.RestartCount == 0 { if m.container.RestartCount == 0 {
m.resetContainer() m.resetContainer(false)
return err return err
} }
@ -154,7 +154,7 @@ func (m *containerMonitor) Start() error {
if m.shouldRestart(exitStatus) { if m.shouldRestart(exitStatus) {
m.container.State.SetRestarting(exitStatus) m.container.State.SetRestarting(exitStatus)
m.container.LogEvent("die") m.container.LogEvent("die")
m.resetContainer() m.resetContainer(true)
// sleep with a small time increment between each restart to help avoid issues cased by quickly // sleep with a small time increment between each restart to help avoid issues cased by quickly
// restarting the container because of some types of errors ( networking cut out, etc... ) // restarting the container because of some types of errors ( networking cut out, etc... )
@ -168,7 +168,7 @@ func (m *containerMonitor) Start() error {
continue continue
} }
m.container.LogEvent("die") m.container.LogEvent("die")
m.resetContainer() m.resetContainer(true)
return err return err
} }
} }
@ -243,7 +243,7 @@ func (m *containerMonitor) callback(command *execdriver.Command) {
} }
} }
m.container.State.SetRunning(command.Pid()) m.container.State.setRunning(command.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
@ -260,8 +260,13 @@ func (m *containerMonitor) callback(command *execdriver.Command) {
// resetContainer resets the container's IO and ensures that the command is able to be executed again // resetContainer resets the container's IO and ensures that the command is able to be executed again
// by copying the data into a new struct // by copying the data into a new struct
func (m *containerMonitor) resetContainer() { // if lock is true, then container locked during reset
func (m *containerMonitor) resetContainer(lock bool) {
container := m.container container := m.container
if lock {
container.Lock()
defer container.Unlock()
}
if container.Config.OpenStdin { if container.Config.OpenStdin {
if err := container.stdin.Close(); err != nil { if err := container.stdin.Close(); err != nil {

View file

@ -1,7 +1,6 @@
package daemon package daemon
import ( import (
"encoding/json"
"fmt" "fmt"
"sync" "sync"
"time" "time"
@ -10,7 +9,7 @@ import (
) )
type State struct { type State struct {
sync.RWMutex sync.Mutex
Running bool Running bool
Paused bool Paused bool
Restarting bool Restarting bool
@ -29,9 +28,6 @@ func NewState() *State {
// String returns a human-readable description of the state // String returns a human-readable description of the state
func (s *State) String() string { func (s *State) String() string {
s.RLock()
defer s.RUnlock()
if s.Running { if s.Running {
if s.Paused { if s.Paused {
return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt)))
@ -50,16 +46,6 @@ func (s *State) String() string {
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
} }
type jState State
// MarshalJSON for state is needed to avoid race conditions on inspect
func (s *State) MarshalJSON() ([]byte, error) {
s.RLock()
b, err := json.Marshal(jState(*s))
s.RUnlock()
return b, err
}
func wait(waitChan <-chan struct{}, timeout time.Duration) error { func wait(waitChan <-chan struct{}, timeout time.Duration) error {
if timeout < 0 { if timeout < 0 {
<-waitChan <-waitChan
@ -77,14 +63,14 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
// immediatly. If you want wait forever you must supply negative timeout. // immediatly. If you want wait forever you must supply negative timeout.
// Returns pid, that was passed to SetRunning // Returns pid, that was passed to SetRunning
func (s *State) WaitRunning(timeout time.Duration) (int, error) { func (s *State) WaitRunning(timeout time.Duration) (int, error) {
s.RLock() s.Lock()
if s.IsRunning() { if s.Running {
pid := s.Pid pid := s.Pid
s.RUnlock() s.Unlock()
return pid, nil return pid, nil
} }
waitChan := s.waitChan waitChan := s.waitChan
s.RUnlock() s.Unlock()
if err := wait(waitChan, timeout); err != nil { if err := wait(waitChan, timeout); err != nil {
return -1, err return -1, err
} }
@ -95,14 +81,14 @@ func (s *State) WaitRunning(timeout time.Duration) (int, error) {
// immediatly. If you want wait forever you must supply negative timeout. // immediatly. If you want wait forever you must supply negative timeout.
// Returns exit code, that was passed to SetStopped // Returns exit code, that was passed to SetStopped
func (s *State) WaitStop(timeout time.Duration) (int, error) { func (s *State) WaitStop(timeout time.Duration) (int, error) {
s.RLock() s.Lock()
if !s.Running { if !s.Running {
exitCode := s.ExitCode exitCode := s.ExitCode
s.RUnlock() s.Unlock()
return exitCode, nil return exitCode, nil
} }
waitChan := s.waitChan waitChan := s.waitChan
s.RUnlock() s.Unlock()
if err := wait(waitChan, timeout); err != nil { if err := wait(waitChan, timeout); err != nil {
return -1, err return -1, err
} }
@ -110,28 +96,33 @@ func (s *State) WaitStop(timeout time.Duration) (int, error) {
} }
func (s *State) IsRunning() bool { func (s *State) IsRunning() bool {
s.RLock() s.Lock()
res := s.Running res := s.Running
s.RUnlock() s.Unlock()
return res return res
} }
func (s *State) GetPid() int { func (s *State) GetPid() int {
s.RLock() s.Lock()
res := s.Pid res := s.Pid
s.RUnlock() s.Unlock()
return res return res
} }
func (s *State) GetExitCode() int { func (s *State) GetExitCode() int {
s.RLock() s.Lock()
res := s.ExitCode res := s.ExitCode
s.RUnlock() s.Unlock()
return res return res
} }
func (s *State) SetRunning(pid int) { func (s *State) SetRunning(pid int) {
s.Lock() s.Lock()
s.setRunning(pid)
s.Unlock()
}
func (s *State) setRunning(pid int) {
s.Running = true s.Running = true
s.Paused = false s.Paused = false
s.Restarting = false s.Restarting = false
@ -140,11 +131,15 @@ func (s *State) SetRunning(pid int) {
s.StartedAt = time.Now().UTC() s.StartedAt = time.Now().UTC()
close(s.waitChan) // fire waiters for start close(s.waitChan) // fire waiters for start
s.waitChan = make(chan struct{}) s.waitChan = make(chan struct{})
s.Unlock()
} }
func (s *State) SetStopped(exitCode int) { func (s *State) SetStopped(exitCode int) {
s.Lock() s.Lock()
s.setStopped(exitCode)
s.Unlock()
}
func (s *State) setStopped(exitCode int) {
s.Running = false s.Running = false
s.Restarting = false s.Restarting = false
s.Pid = 0 s.Pid = 0
@ -152,7 +147,6 @@ func (s *State) SetStopped(exitCode int) {
s.ExitCode = exitCode s.ExitCode = exitCode
close(s.waitChan) // fire waiters for stop close(s.waitChan) // fire waiters for stop
s.waitChan = make(chan struct{}) s.waitChan = make(chan struct{})
s.Unlock()
} }
// SetRestarting is when docker hanldes the auto restart of containers when they are // SetRestarting is when docker hanldes the auto restart of containers when they are
@ -172,9 +166,9 @@ func (s *State) SetRestarting(exitCode int) {
} }
func (s *State) IsRestarting() bool { func (s *State) IsRestarting() bool {
s.RLock() s.Lock()
res := s.Restarting res := s.Restarting
s.RUnlock() s.Unlock()
return res return res
} }
@ -191,8 +185,8 @@ func (s *State) SetUnpaused() {
} }
func (s *State) IsPaused() bool { func (s *State) IsPaused() bool {
s.RLock() s.Lock()
res := s.Paused res := s.Paused
s.RUnlock() s.Unlock()
return res return res
} }