Browse code

Remove the mutexes and use chan instead in order to handle the wait lock

Guillaume J. Charmes authored on 2013/04/09 23:57:59
Showing 3 changed files
... ...
@@ -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
 }