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  }