github.com/schwarzm/garden-linux@v0.0.0-20150507151835-33bca2147c47/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 ) 11 12 type ProcessTracker interface { 13 Run(processID uint32, cmd *exec.Cmd, io garden.ProcessIO, tty *garden.TTYSpec, signaller Signaller) (garden.Process, error) 14 Attach(processID uint32, io garden.ProcessIO) (garden.Process, error) 15 Restore(processID uint32, signaller Signaller) 16 ActiveProcesses() []garden.Process 17 } 18 19 type processTracker struct { 20 containerPath string 21 runner command_runner.CommandRunner 22 23 processes map[uint32]*Process 24 processesMutex *sync.RWMutex 25 } 26 27 type UnknownProcessError struct { 28 ProcessID uint32 29 } 30 31 func (e UnknownProcessError) Error() string { 32 return fmt.Sprintf("process_tracker: unknown process: %d", e.ProcessID) 33 } 34 35 func New(containerPath string, runner command_runner.CommandRunner) ProcessTracker { 36 return &processTracker{ 37 containerPath: containerPath, 38 runner: runner, 39 40 processesMutex: new(sync.RWMutex), 41 processes: make(map[uint32]*Process), 42 } 43 } 44 45 func (t *processTracker) Run(processID uint32, cmd *exec.Cmd, processIO garden.ProcessIO, tty *garden.TTYSpec, signaller Signaller) (garden.Process, error) { 46 t.processesMutex.Lock() 47 process := NewProcess(processID, t.containerPath, t.runner, signaller) 48 t.processes[processID] = process 49 t.processesMutex.Unlock() 50 51 ready, active := process.Spawn(cmd, tty) 52 53 err := <-ready 54 if err != nil { 55 return nil, err 56 } 57 58 process.Attach(processIO) 59 60 go t.link(process.ID()) 61 62 err = <-active 63 if err != nil { 64 return nil, err 65 } 66 67 return process, nil 68 } 69 70 func (t *processTracker) Attach(processID uint32, processIO garden.ProcessIO) (garden.Process, error) { 71 t.processesMutex.RLock() 72 process, ok := t.processes[processID] 73 t.processesMutex.RUnlock() 74 75 if !ok { 76 return nil, UnknownProcessError{processID} 77 } 78 79 process.Attach(processIO) 80 81 go t.link(processID) 82 83 return process, nil 84 } 85 86 func (t *processTracker) Restore(processID uint32, signaller Signaller) { 87 t.processesMutex.Lock() 88 89 process := NewProcess(processID, t.containerPath, t.runner, signaller) 90 91 t.processes[processID] = process 92 93 go t.link(processID) 94 95 t.processesMutex.Unlock() 96 } 97 98 func (t *processTracker) ActiveProcesses() []garden.Process { 99 t.processesMutex.RLock() 100 defer t.processesMutex.RUnlock() 101 102 processes := make([]garden.Process, len(t.processes)) 103 104 i := 0 105 for _, process := range t.processes { 106 processes[i] = process 107 i++ 108 } 109 110 return processes 111 } 112 113 func (t *processTracker) link(processID uint32) { 114 t.processesMutex.RLock() 115 process, ok := t.processes[processID] 116 t.processesMutex.RUnlock() 117 118 if !ok { 119 return 120 } 121 122 defer t.unregister(processID) 123 124 process.Link() 125 126 return 127 } 128 129 func (t *processTracker) unregister(processID uint32) { 130 t.processesMutex.Lock() 131 defer t.processesMutex.Unlock() 132 133 delete(t.processes, processID) 134 }