github.com/chenchun/docker@v1.3.2-0.20150629222414-20467faf132b/daemon/state.go (about) 1 package daemon 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 "github.com/docker/docker/daemon/execdriver" 9 "github.com/docker/docker/pkg/units" 10 ) 11 12 type State struct { 13 sync.Mutex 14 Running bool 15 Paused bool 16 Restarting bool 17 OOMKilled bool 18 removalInProgress bool // Not need for this to be persistent on disk. 19 Dead bool 20 Pid int 21 ExitCode int 22 Error string // contains last known error when starting the container 23 StartedAt time.Time 24 FinishedAt time.Time 25 waitChan chan struct{} 26 } 27 28 func NewState() *State { 29 return &State{ 30 waitChan: make(chan struct{}), 31 } 32 } 33 34 // String returns a human-readable description of the state 35 func (s *State) String() string { 36 if s.Running { 37 if s.Paused { 38 return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 39 } 40 if s.Restarting { 41 return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 42 } 43 44 return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 45 } 46 47 if s.removalInProgress { 48 return "Removal In Progress" 49 } 50 51 if s.Dead { 52 return "Dead" 53 } 54 55 if s.StartedAt.IsZero() { 56 return "Created" 57 } 58 59 if s.FinishedAt.IsZero() { 60 return "" 61 } 62 63 return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 64 } 65 66 // StateString returns a single string to describe state 67 func (s *State) StateString() string { 68 if s.Running { 69 if s.Paused { 70 return "paused" 71 } 72 if s.Restarting { 73 return "restarting" 74 } 75 return "running" 76 } 77 78 if s.Dead { 79 return "dead" 80 } 81 82 if s.StartedAt.IsZero() { 83 return "created" 84 } 85 86 return "exited" 87 } 88 89 func wait(waitChan <-chan struct{}, timeout time.Duration) error { 90 if timeout < 0 { 91 <-waitChan 92 return nil 93 } 94 select { 95 case <-time.After(timeout): 96 return fmt.Errorf("Timed out: %v", timeout) 97 case <-waitChan: 98 return nil 99 } 100 } 101 102 // WaitRunning waits until state is running. If state already running it returns 103 // immediately. If you want wait forever you must supply negative timeout. 104 // Returns pid, that was passed to SetRunning 105 func (s *State) WaitRunning(timeout time.Duration) (int, error) { 106 s.Lock() 107 if s.Running { 108 pid := s.Pid 109 s.Unlock() 110 return pid, nil 111 } 112 waitChan := s.waitChan 113 s.Unlock() 114 if err := wait(waitChan, timeout); err != nil { 115 return -1, err 116 } 117 return s.GetPid(), nil 118 } 119 120 // WaitStop waits until state is stopped. If state already stopped it returns 121 // immediately. If you want wait forever you must supply negative timeout. 122 // Returns exit code, that was passed to SetStopped 123 func (s *State) WaitStop(timeout time.Duration) (int, error) { 124 s.Lock() 125 if !s.Running { 126 exitCode := s.ExitCode 127 s.Unlock() 128 return exitCode, nil 129 } 130 waitChan := s.waitChan 131 s.Unlock() 132 if err := wait(waitChan, timeout); err != nil { 133 return -1, err 134 } 135 return s.GetExitCode(), nil 136 } 137 138 func (s *State) IsRunning() bool { 139 s.Lock() 140 res := s.Running 141 s.Unlock() 142 return res 143 } 144 145 func (s *State) GetPid() int { 146 s.Lock() 147 res := s.Pid 148 s.Unlock() 149 return res 150 } 151 152 func (s *State) GetExitCode() int { 153 s.Lock() 154 res := s.ExitCode 155 s.Unlock() 156 return res 157 } 158 159 func (s *State) SetRunning(pid int) { 160 s.Lock() 161 s.setRunning(pid) 162 s.Unlock() 163 } 164 165 func (s *State) setRunning(pid int) { 166 s.Error = "" 167 s.Running = true 168 s.Paused = false 169 s.Restarting = false 170 s.ExitCode = 0 171 s.Pid = pid 172 s.StartedAt = time.Now().UTC() 173 close(s.waitChan) // fire waiters for start 174 s.waitChan = make(chan struct{}) 175 } 176 177 func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) { 178 s.Lock() 179 s.setStopped(exitStatus) 180 s.Unlock() 181 } 182 183 func (s *State) setStopped(exitStatus *execdriver.ExitStatus) { 184 s.Running = false 185 s.Restarting = false 186 s.Pid = 0 187 s.FinishedAt = time.Now().UTC() 188 s.ExitCode = exitStatus.ExitCode 189 s.OOMKilled = exitStatus.OOMKilled 190 close(s.waitChan) // fire waiters for stop 191 s.waitChan = make(chan struct{}) 192 } 193 194 // SetRestarting is when docker handles the auto restart of containers when they are 195 // in the middle of a stop and being restarted again 196 func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) { 197 s.Lock() 198 // we should consider the container running when it is restarting because of 199 // all the checks in docker around rm/stop/etc 200 s.Running = true 201 s.Restarting = true 202 s.Pid = 0 203 s.FinishedAt = time.Now().UTC() 204 s.ExitCode = exitStatus.ExitCode 205 s.OOMKilled = exitStatus.OOMKilled 206 close(s.waitChan) // fire waiters for stop 207 s.waitChan = make(chan struct{}) 208 s.Unlock() 209 } 210 211 // setError sets the container's error state. This is useful when we want to 212 // know the error that occurred when container transits to another state 213 // when inspecting it 214 func (s *State) setError(err error) { 215 s.Error = err.Error() 216 } 217 218 func (s *State) IsRestarting() bool { 219 s.Lock() 220 res := s.Restarting 221 s.Unlock() 222 return res 223 } 224 225 func (s *State) SetPaused() { 226 s.Lock() 227 s.Paused = true 228 s.Unlock() 229 } 230 231 func (s *State) SetUnpaused() { 232 s.Lock() 233 s.Paused = false 234 s.Unlock() 235 } 236 237 func (s *State) IsPaused() bool { 238 s.Lock() 239 res := s.Paused 240 s.Unlock() 241 return res 242 } 243 244 func (s *State) SetRemovalInProgress() error { 245 s.Lock() 246 defer s.Unlock() 247 if s.removalInProgress { 248 return fmt.Errorf("Status is already RemovalInProgress") 249 } 250 s.removalInProgress = true 251 return nil 252 } 253 254 func (s *State) ResetRemovalInProgress() { 255 s.Lock() 256 s.removalInProgress = false 257 s.Unlock() 258 } 259 260 func (s *State) SetDead() { 261 s.Lock() 262 s.Dead = true 263 s.Unlock() 264 }