... | ... |
@@ -43,6 +43,8 @@ type Container struct { |
43 | 43 |
ptyMaster io.Closer |
44 | 44 |
|
45 | 45 |
runtime *Runtime |
46 |
+ |
|
47 |
+ waitLock chan struct{} |
|
46 | 48 |
} |
47 | 49 |
|
48 | 50 |
type Config struct { |
... | ... |
@@ -406,6 +408,10 @@ func (container *Container) Start() error { |
406 | 406 |
// FIXME: save state on disk *first*, then converge |
407 | 407 |
// this way disk state is used as a journal, eg. we can restore after crash etc. |
408 | 408 |
container.State.setRunning(container.cmd.Process.Pid) |
409 |
+ |
|
410 |
+ // Init the lock |
|
411 |
+ container.waitLock = make(chan struct{}) |
|
412 |
+ |
|
409 | 413 |
container.ToDisk() |
410 | 414 |
go container.monitor() |
411 | 415 |
return nil |
... | ... |
@@ -522,6 +528,10 @@ func (container *Container) monitor() { |
522 | 522 |
|
523 | 523 |
// Report status back |
524 | 524 |
container.State.setStopped(exitCode) |
525 |
+ |
|
526 |
+ // Release the lock |
|
527 |
+ close(container.waitLock) |
|
528 |
+ |
|
525 | 529 |
if err := container.ToDisk(); err != nil { |
526 | 530 |
// FIXME: there is a race condition here which causes this to fail during the unit tests. |
527 | 531 |
// If another goroutine was waiting for Wait() to return before removing the container's root |
... | ... |
@@ -588,10 +598,7 @@ func (container *Container) Restart() error { |
588 | 588 |
|
589 | 589 |
// Wait blocks until the container stops running, then returns its exit code. |
590 | 590 |
func (container *Container) Wait() int { |
591 |
- |
|
592 |
- for container.State.Running { |
|
593 |
- container.State.wait() |
|
594 |
- } |
|
591 |
+ <-container.waitLock |
|
595 | 592 |
return container.State.ExitCode |
596 | 593 |
} |
597 | 594 |
|
... | ... |
@@ -116,7 +116,6 @@ func (runtime *Runtime) Load(id string) (*Container, error) { |
116 | 116 |
if err := container.FromDisk(); err != nil { |
117 | 117 |
return nil, err |
118 | 118 |
} |
119 |
- container.State.initLock() |
|
120 | 119 |
if container.Id != id { |
121 | 120 |
return container, fmt.Errorf("Container %s is stored at %s", container.Id, id) |
122 | 121 |
} |
... | ... |
@@ -136,6 +135,7 @@ func (runtime *Runtime) Register(container *Container) error { |
136 | 136 |
} |
137 | 137 |
|
138 | 138 |
// FIXME: if the container is supposed to be running but is not, auto restart it? |
139 |
+ // if so, then we need to restart monitor and init a new lock |
|
139 | 140 |
// If the container is supposed to be running, make sure of it |
140 | 141 |
if container.State.Running { |
141 | 142 |
if output, err := exec.Command("lxc-info", "-n", container.Id).CombinedOutput(); err != nil { |
... | ... |
@@ -152,8 +152,7 @@ func (runtime *Runtime) Register(container *Container) error { |
152 | 152 |
} |
153 | 153 |
|
154 | 154 |
container.runtime = runtime |
155 |
- // Setup state lock (formerly in newState() |
|
156 |
- container.State.initLock() |
|
155 |
+ |
|
157 | 156 |
// Attach to stdout and stderr |
158 | 157 |
container.stderr = newWriteBroadcaster() |
159 | 158 |
container.stdout = newWriteBroadcaster() |
... | ... |
@@ -2,7 +2,6 @@ package docker |
2 | 2 |
|
3 | 3 |
import ( |
4 | 4 |
"fmt" |
5 |
- "sync" |
|
6 | 5 |
"time" |
7 | 6 |
) |
8 | 7 |
|
... | ... |
@@ -11,9 +10,6 @@ type State struct { |
11 | 11 |
Pid int |
12 | 12 |
ExitCode int |
13 | 13 |
StartedAt time.Time |
14 |
- |
|
15 |
- stateChangeLock *sync.Mutex |
|
16 |
- stateChangeCond *sync.Cond |
|
17 | 14 |
} |
18 | 15 |
|
19 | 16 |
// String returns a human-readable description of the state |
... | ... |
@@ -29,31 +25,10 @@ func (s *State) setRunning(pid int) { |
29 | 29 |
s.ExitCode = 0 |
30 | 30 |
s.Pid = pid |
31 | 31 |
s.StartedAt = time.Now() |
32 |
- s.broadcast() |
|
33 | 32 |
} |
34 | 33 |
|
35 | 34 |
func (s *State) setStopped(exitCode int) { |
36 | 35 |
s.Running = false |
37 | 36 |
s.Pid = 0 |
38 | 37 |
s.ExitCode = exitCode |
39 |
- s.broadcast() |
|
40 |
-} |
|
41 |
- |
|
42 |
-func (s *State) initLock() { |
|
43 |
- if s.stateChangeLock == nil { |
|
44 |
- s.stateChangeLock = &sync.Mutex{} |
|
45 |
- s.stateChangeCond = sync.NewCond(s.stateChangeLock) |
|
46 |
- } |
|
47 |
-} |
|
48 |
- |
|
49 |
-func (s *State) broadcast() { |
|
50 |
- s.stateChangeLock.Lock() |
|
51 |
- s.stateChangeCond.Broadcast() |
|
52 |
- s.stateChangeLock.Unlock() |
|
53 |
-} |
|
54 |
- |
|
55 |
-func (s *State) wait() { |
|
56 |
- s.stateChangeLock.Lock() |
|
57 |
- s.stateChangeCond.Wait() |
|
58 |
- s.stateChangeLock.Unlock() |
|
59 | 38 |
} |