github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/process_tracker/process_tracker.go (about) 1 package process_tracker 2 3 import ( 4 "fmt" 5 "os/exec" 6 "sync" 7 8 "github.com/cloudfoundry-incubator/garden" 9 "github.com/cloudfoundry/gunk/command_runner" 10 "github.com/pivotal-golang/lager" 11 ) 12 13 //go:generate counterfeiter -o fake_process_tracker/fake_process_tracker.go . ProcessTracker 14 type ProcessTracker interface { 15 Run(processID string, cmd *exec.Cmd, io garden.ProcessIO, tty *garden.TTYSpec, signaller Signaller) (garden.Process, error) 16 Attach(processID string, io garden.ProcessIO) (garden.Process, error) 17 Restore(processID string, signaller Signaller) 18 ActiveProcesses() []garden.Process 19 } 20 21 type processTracker struct { 22 logger lager.Logger 23 containerPath string 24 runner command_runner.CommandRunner 25 26 processes map[string]*Process 27 processesMutex *sync.RWMutex 28 } 29 30 type UnknownProcessError struct { 31 ProcessID string 32 } 33 34 func (e UnknownProcessError) Error() string { 35 return fmt.Sprintf("process_tracker: unknown process: %s", e.ProcessID) 36 } 37 38 func New(logger lager.Logger, containerPath string, runner command_runner.CommandRunner) ProcessTracker { 39 return &processTracker{ 40 logger: logger, 41 42 containerPath: containerPath, 43 runner: runner, 44 45 processesMutex: new(sync.RWMutex), 46 processes: make(map[string]*Process), 47 } 48 } 49 50 func (t *processTracker) Run(processID string, cmd *exec.Cmd, processIO garden.ProcessIO, tty *garden.TTYSpec, signaller Signaller) (garden.Process, error) { 51 t.processesMutex.Lock() 52 process := NewProcess(t.logger.Session("process", lager.Data{"id": processID}), processID, t.containerPath, t.runner, signaller) 53 t.processes[processID] = process 54 t.processesMutex.Unlock() 55 56 t.logger.Info("run-spawning", lager.Data{"id": processID, "cmd": cmd}) 57 ready, active := process.Spawn(cmd, tty) 58 t.logger.Info("run-spawned", lager.Data{"id": processID, "cmd": cmd}) 59 60 t.logger.Info("waiting-iodaemon-ready") 61 err := <-ready 62 if err != nil { 63 t.logger.Error("reading-ready-failed", err) 64 return nil, err 65 } 66 t.logger.Info("iodaemon-ready") 67 68 t.logger.Info("attaching") 69 process.Attach(processIO) 70 t.logger.Info("attached") 71 72 go t.link(process.ID()) 73 74 t.logger.Info("waiting-iodaemon-active") 75 err = <-active 76 if err != nil { 77 t.logger.Error("reading-active-failed", err) 78 return nil, err 79 } 80 t.logger.Info("iodaemon-active") 81 82 return process, nil 83 } 84 85 func (t *processTracker) Attach(processID string, processIO garden.ProcessIO) (garden.Process, error) { 86 t.processesMutex.RLock() 87 process, ok := t.processes[processID] 88 t.processesMutex.RUnlock() 89 90 if !ok { 91 return nil, UnknownProcessError{processID} 92 } 93 94 process.Attach(processIO) 95 96 go t.link(processID) 97 98 return process, nil 99 } 100 101 func (t *processTracker) Restore(processID string, signaller Signaller) { 102 t.processesMutex.Lock() 103 104 process := NewProcess(t.logger, processID, t.containerPath, t.runner, signaller) 105 106 t.processes[processID] = process 107 108 go t.link(processID) 109 110 t.processesMutex.Unlock() 111 } 112 113 func (t *processTracker) ActiveProcesses() []garden.Process { 114 t.processesMutex.RLock() 115 defer t.processesMutex.RUnlock() 116 117 processes := make([]garden.Process, 0) 118 for _, process := range t.processes { 119 processes = append(processes, process) 120 } 121 122 return processes 123 } 124 125 func (t *processTracker) link(processID string) { 126 t.logger.Info("link-start") 127 t.processesMutex.RLock() 128 process, ok := t.processes[processID] 129 t.processesMutex.RUnlock() 130 t.logger.Info("got-process-from-mutex-map") 131 132 if !ok { 133 return 134 } 135 136 defer t.unregister(processID) 137 138 process.Link() 139 140 return 141 } 142 143 func (t *processTracker) unregister(processID string) { 144 t.processesMutex.Lock() 145 defer t.processesMutex.Unlock() 146 147 t.logger.Info("unregistering", lager.Data{"id": processID}) 148 delete(t.processes, processID) 149 }