Bläddra i källkod

Merge pull request #7582 from LK4D4/fix_races

Fix some race conditions
Victor Vieux 11 år sedan
förälder
incheckning
5a1e4a1092
2 ändrade filer med 31 tillägg och 6 borttagningar
  1. 20 6
      daemon/monitor.go
  2. 11 0
      daemon/state.go

+ 20 - 6
daemon/monitor.go

@@ -58,8 +58,8 @@ func newContainerMonitor(container *Container, policy runconfig.RestartPolicy) *
 		container:     container,
 		restartPolicy: policy,
 		timeIncrement: defaultTimeIncrement,
-		stopChan:      make(chan struct{}, 1),
-		startSignal:   make(chan struct{}, 1),
+		stopChan:      make(chan struct{}),
+		startSignal:   make(chan struct{}),
 	}
 }
 
@@ -103,8 +103,17 @@ func (m *containerMonitor) Start() error {
 		exitStatus int
 	)
 
+	// this variable indicates that we under container.Lock
+	underLock := true
+
 	// ensure that when the monitor finally exits we release the networking and unmount the rootfs
-	defer m.Close()
+	defer func() {
+		if !underLock {
+			m.container.Lock()
+			defer m.container.Unlock()
+		}
+		m.Close()
+	}()
 
 	// reset the restart count
 	m.container.RestartCount = -1
@@ -136,6 +145,9 @@ func (m *containerMonitor) Start() error {
 			log.Errorf("Error running container: %s", err)
 		}
 
+		// here container.Lock is already lost
+		underLock = false
+
 		m.resetMonitor(err == nil && exitStatus == 0)
 
 		if m.shouldRestart(exitStatus) {
@@ -244,10 +256,12 @@ func (m *containerMonitor) callback(command *execdriver.Command) {
 
 	m.container.State.SetRunning(command.Pid())
 
-	if m.startSignal != nil {
-		// signal that the process has started
+	// signal that the process has started
+	// close channel only if not closed
+	select {
+	case <-m.startSignal:
+	default:
 		close(m.startSignal)
-		m.startSignal = nil
 	}
 
 	if err := m.container.ToDisk(); err != nil {

+ 11 - 0
daemon/state.go

@@ -1,6 +1,7 @@
 package daemon
 
 import (
+	"encoding/json"
 	"fmt"
 	"sync"
 	"time"
@@ -49,6 +50,16 @@ func (s *State) String() string {
 	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 {
 	if timeout < 0 {
 		<-waitChan