Browse code

Merge pull request #7582 from LK4D4/fix_races

Fix some race conditions

Victor Vieux authored on 2014/08/15 06:35:04
Showing 2 changed files
... ...
@@ -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