| ... | ... |
@@ -58,8 +58,8 @@ func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) * |
| 58 | 58 |
container: container, |
| 59 | 59 |
restartPolicy: policy, |
| 60 | 60 |
timeIncrement: defaultTimeIncrement, |
| 61 |
- stopChan: make(chan struct{}, 1),
|
|
| 62 |
- startSignal: make(chan struct{}, 1),
|
|
| 61 |
+ stopChan: make(chan struct{}),
|
|
| 62 |
+ startSignal: make(chan struct{}),
|
|
| 63 | 63 |
} |
| 64 | 64 |
} |
| 65 | 65 |
|
| ... | ... |
@@ -103,8 +103,17 @@ func (m *containerMonitor) Start() error {
|
| 103 | 103 |
exitStatus int |
| 104 | 104 |
) |
| 105 | 105 |
|
| 106 |
+ // this variable indicates that we under container.Lock |
|
| 107 |
+ underLock := true |
|
| 108 |
+ |
|
| 106 | 109 |
// ensure that when the monitor finally exits we release the networking and unmount the rootfs |
| 107 |
- defer m.Close() |
|
| 110 |
+ defer func() {
|
|
| 111 |
+ if !underLock {
|
|
| 112 |
+ m.container.Lock() |
|
| 113 |
+ defer m.container.Unlock() |
|
| 114 |
+ } |
|
| 115 |
+ m.Close() |
|
| 116 |
+ }() |
|
| 108 | 117 |
|
| 109 | 118 |
// reset the restart count |
| 110 | 119 |
m.container.RestartCount = -1 |
| ... | ... |
@@ -136,6 +145,9 @@ func (m *containerMonitor) Start() error {
|
| 136 | 136 |
log.Errorf("Error running container: %s", err)
|
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
+ // here container.Lock is already lost |
|
| 140 |
+ underLock = false |
|
| 141 |
+ |
|
| 139 | 142 |
m.resetMonitor(err == nil && exitStatus == 0) |
| 140 | 143 |
|
| 141 | 144 |
if m.shouldRestart(exitStatus) {
|
| ... | ... |
@@ -244,10 +256,12 @@ func (m *containerMonitor) callback(command *execdriver.Command) {
|
| 244 | 244 |
|
| 245 | 245 |
m.container.State.SetRunning(command.Pid()) |
| 246 | 246 |
|
| 247 |
- if m.startSignal != nil {
|
|
| 248 |
- // signal that the process has started |
|
| 247 |
+ // signal that the process has started |
|
| 248 |
+ // close channel only if not closed |
|
| 249 |
+ select {
|
|
| 250 |
+ case <-m.startSignal: |
|
| 251 |
+ default: |
|
| 249 | 252 |
close(m.startSignal) |
| 250 |
- m.startSignal = nil |
|
| 251 | 253 |
} |
| 252 | 254 |
|
| 253 | 255 |
if err := m.container.ToDisk(); err != nil {
|
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/json" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"sync" |
| 6 | 7 |
"time" |
| ... | ... |
@@ -49,6 +50,16 @@ func (s *State) String() string {
|
| 49 | 49 |
return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)))
|
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
+type jState State |
|
| 53 |
+ |
|
| 54 |
+// MarshalJSON for state is needed to avoid race conditions on inspect |
|
| 55 |
+func (s *State) MarshalJSON() ([]byte, error) {
|
|
| 56 |
+ s.RLock() |
|
| 57 |
+ b, err := json.Marshal(jState(*s)) |
|
| 58 |
+ s.RUnlock() |
|
| 59 |
+ return b, err |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 52 | 62 |
func wait(waitChan <-chan struct{}, timeout time.Duration) error {
|
| 53 | 63 |
if timeout < 0 {
|
| 54 | 64 |
<-waitChan |