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  }