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  }