diff --git a/container.go b/container.go index 6b3913522..37899e57a 100644 --- a/container.go +++ b/container.go @@ -43,6 +43,8 @@ type Container struct { ptyMaster io.Closer runtime *Runtime + + waitLock chan struct{} } type Config struct { @@ -406,6 +408,10 @@ func (container *Container) Start() error { // FIXME: save state on disk *first*, then converge // this way disk state is used as a journal, eg. we can restore after crash etc. container.State.setRunning(container.cmd.Process.Pid) + + // Init the lock + container.waitLock = make(chan struct{}) + container.ToDisk() go container.monitor() return nil @@ -522,6 +528,10 @@ func (container *Container) monitor() { // Report status back container.State.setStopped(exitCode) + + // Release the lock + close(container.waitLock) + if err := container.ToDisk(); err != nil { // FIXME: there is a race condition here which causes this to fail during the unit tests. // If another goroutine was waiting for Wait() to return before removing the container's root @@ -588,10 +598,7 @@ func (container *Container) Restart() error { // Wait blocks until the container stops running, then returns its exit code. func (container *Container) Wait() int { - - for container.State.Running { - container.State.wait() - } + <-container.waitLock return container.State.ExitCode } diff --git a/runtime.go b/runtime.go index 0e5bcbfc6..64a0c876d 100644 --- a/runtime.go +++ b/runtime.go @@ -116,7 +116,6 @@ func (runtime *Runtime) Load(id string) (*Container, error) { if err := container.FromDisk(); err != nil { return nil, err } - container.State.initLock() if container.Id != id { return container, fmt.Errorf("Container %s is stored at %s", container.Id, id) } @@ -136,6 +135,7 @@ func (runtime *Runtime) Register(container *Container) error { } // FIXME: if the container is supposed to be running but is not, auto restart it? + // if so, then we need to restart monitor and init a new lock // If the container is supposed to be running, make sure of it if container.State.Running { if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil { @@ -152,8 +152,7 @@ func (runtime *Runtime) Register(container *Container) error { } container.runtime = runtime - // Setup state lock (formerly in newState() - container.State.initLock() + // Attach to stdout and stderr container.stderr = newWriteBroadcaster() container.stdout = newWriteBroadcaster() diff --git a/state.go b/state.go index bf325a3ea..cde999f3a 100644 --- a/state.go +++ b/state.go @@ -2,7 +2,6 @@ package docker import ( "fmt" - "sync" "time" ) @@ -11,9 +10,6 @@ type State struct { Pid int ExitCode int StartedAt time.Time - - stateChangeLock *sync.Mutex - stateChangeCond *sync.Cond } // String returns a human-readable description of the state @@ -29,31 +25,10 @@ func (s *State) setRunning(pid int) { s.ExitCode = 0 s.Pid = pid s.StartedAt = time.Now() - s.broadcast() } func (s *State) setStopped(exitCode int) { s.Running = false s.Pid = 0 s.ExitCode = exitCode - s.broadcast() -} - -func (s *State) initLock() { - if s.stateChangeLock == nil { - s.stateChangeLock = &sync.Mutex{} - s.stateChangeCond = sync.NewCond(s.stateChangeLock) - } -} - -func (s *State) broadcast() { - s.stateChangeLock.Lock() - s.stateChangeCond.Broadcast() - s.stateChangeLock.Unlock() -} - -func (s *State) wait() { - s.stateChangeLock.Lock() - s.stateChangeCond.Wait() - s.stateChangeLock.Unlock() }