github.com/fcwu/docker@v1.4.2-0.20150115145920-2a69ca89f0df/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 Pid int 19 ExitCode int 20 Error string // contains last known error when starting the container 21 StartedAt time.Time 22 FinishedAt time.Time 23 waitChan chan struct{} 24 } 25 26 func NewState() *State { 27 return &State{ 28 waitChan: make(chan struct{}), 29 } 30 } 31 32 // String returns a human-readable description of the state 33 func (s *State) String() string { 34 if s.Running { 35 if s.Paused { 36 return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 37 } 38 if s.Restarting { 39 return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 40 } 41 42 return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) 43 } 44 45 if s.FinishedAt.IsZero() { 46 return "" 47 } 48 49 return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) 50 } 51 52 // StateString returns a single string to describe state 53 func (s *State) StateString() string { 54 if s.Running { 55 if s.Paused { 56 return "paused" 57 } 58 if s.Restarting { 59 return "restarting" 60 } 61 return "running" 62 } 63 return "exited" 64 } 65 66 func wait(waitChan <-chan struct{}, timeout time.Duration) error { 67 if timeout < 0 { 68 <-waitChan 69 return nil 70 } 71 select { 72 case <-time.After(timeout): 73 return fmt.Errorf("Timed out: %v", timeout) 74 case <-waitChan: 75 return nil 76 } 77 } 78 79 // WaitRunning waits until state is running. If state already running it returns 80 // immediately. If you want wait forever you must supply negative timeout. 81 // Returns pid, that was passed to SetRunning 82 func (s *State) WaitRunning(timeout time.Duration) (int, error) { 83 s.Lock() 84 if s.Running { 85 pid := s.Pid 86 s.Unlock() 87 return pid, nil 88 } 89 waitChan := s.waitChan 90 s.Unlock() 91 if err := wait(waitChan, timeout); err != nil { 92 return -1, err 93 } 94 return s.GetPid(), nil 95 } 96 97 // WaitStop waits until state is stopped. If state already stopped it returns 98 // immediately. If you want wait forever you must supply negative timeout. 99 // Returns exit code, that was passed to SetStopped 100 func (s *State) WaitStop(timeout time.Duration) (int, error) { 101 s.Lock() 102 if !s.Running { 103 exitCode := s.ExitCode 104 s.Unlock() 105 return exitCode, nil 106 } 107 waitChan := s.waitChan 108 s.Unlock() 109 if err := wait(waitChan, timeout); err != nil { 110 return -1, err 111 } 112 return s.GetExitCode(), nil 113 } 114 115 func (s *State) IsRunning() bool { 116 s.Lock() 117 res := s.Running 118 s.Unlock() 119 return res 120 } 121 122 func (s *State) GetPid() int { 123 s.Lock() 124 res := s.Pid 125 s.Unlock() 126 return res 127 } 128 129 func (s *State) GetExitCode() int { 130 s.Lock() 131 res := s.ExitCode 132 s.Unlock() 133 return res 134 } 135 136 func (s *State) SetRunning(pid int) { 137 s.Lock() 138 s.setRunning(pid) 139 s.Unlock() 140 } 141 142 func (s *State) setRunning(pid int) { 143 s.Error = "" 144 s.Running = true 145 s.Paused = false 146 s.Restarting = false 147 s.ExitCode = 0 148 s.Pid = pid 149 s.StartedAt = time.Now().UTC() 150 close(s.waitChan) // fire waiters for start 151 s.waitChan = make(chan struct{}) 152 } 153 154 func (s *State) SetStopped(exitStatus *execdriver.ExitStatus) { 155 s.Lock() 156 s.setStopped(exitStatus) 157 s.Unlock() 158 } 159 160 func (s *State) setStopped(exitStatus *execdriver.ExitStatus) { 161 s.Running = false 162 s.Restarting = false 163 s.Pid = 0 164 s.FinishedAt = time.Now().UTC() 165 s.ExitCode = exitStatus.ExitCode 166 s.OOMKilled = exitStatus.OOMKilled 167 close(s.waitChan) // fire waiters for stop 168 s.waitChan = make(chan struct{}) 169 } 170 171 // SetRestarting is when docker hanldes the auto restart of containers when they are 172 // in the middle of a stop and being restarted again 173 func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) { 174 s.Lock() 175 // we should consider the container running when it is restarting because of 176 // all the checks in docker around rm/stop/etc 177 s.Running = true 178 s.Restarting = true 179 s.Pid = 0 180 s.FinishedAt = time.Now().UTC() 181 s.ExitCode = exitStatus.ExitCode 182 s.OOMKilled = exitStatus.OOMKilled 183 close(s.waitChan) // fire waiters for stop 184 s.waitChan = make(chan struct{}) 185 s.Unlock() 186 } 187 188 // setError sets the container's error state. This is useful when we want to 189 // know the error that occurred when container transits to another state 190 // when inspecting it 191 func (s *State) setError(err error) { 192 s.Error = err.Error() 193 } 194 195 func (s *State) IsRestarting() bool { 196 s.Lock() 197 res := s.Restarting 198 s.Unlock() 199 return res 200 } 201 202 func (s *State) SetPaused() { 203 s.Lock() 204 s.Paused = true 205 s.Unlock() 206 } 207 208 func (s *State) SetUnpaused() { 209 s.Lock() 210 s.Paused = false 211 s.Unlock() 212 } 213 214 func (s *State) IsPaused() bool { 215 s.Lock() 216 res := s.Paused 217 s.Unlock() 218 return res 219 }