worker.go raw

   1  package pipe
   2  
   3  import (
   4  	"io"
   5  	"os"
   6  	"os/exec"
   7  	"runtime"
   8  	"syscall"
   9  	
  10  	"github.com/p9c/p9/pkg/qu"
  11  )
  12  
  13  type Worker struct {
  14  	Cmd  *exec.Cmd
  15  	Args []string
  16  	// Stderr  io.WriteCloser
  17  	// StdPipe io.ReadCloser
  18  	StdConn *StdConn
  19  }
  20  
  21  // Spawn starts up an arbitrary executable file with given arguments and
  22  // attaches a connection to its stdin/stdout
  23  func Spawn(quit qu.C, args ...string) (w *Worker, e error) {
  24  	w = &Worker{
  25  		Cmd:  exec.Command(args[0], args[1:]...),
  26  		Args: args,
  27  	}
  28  	var cmdOut io.ReadCloser
  29  	if cmdOut, e = w.Cmd.StdoutPipe(); E.Chk(e) {
  30  		return
  31  	}
  32  	var cmdIn io.WriteCloser
  33  	if cmdIn, e = w.Cmd.StdinPipe(); E.Chk(e) {
  34  		return
  35  	}
  36  	w.StdConn = New(cmdOut, cmdIn, quit)
  37  	w.Cmd.Stderr = os.Stderr
  38  	if e = w.Cmd.Start(); E.Chk(e) {
  39  	}
  40  	return
  41  }
  42  
  43  // Wait for the process to finish running
  44  func (w *Worker) Wait() (e error) {
  45  	return w.Cmd.Wait()
  46  }
  47  
  48  // Interrupt the child process.
  49  // This invokes kill on windows because windows doesn't have an interrupt
  50  // signal.
  51  func (w *Worker) Interrupt() (e error) {
  52  	if runtime.GOOS == "windows" {
  53  		if e = w.Cmd.Process.Kill(); E.Chk(e) {
  54  		}
  55  		return
  56  	}
  57  	if e = w.Cmd.Process.Signal(syscall.SIGINT); !E.Chk(e) {
  58  		D.Ln("interrupted")
  59  	}
  60  	return
  61  }
  62  
  63  // Kill forces the child process to shut down without cleanup
  64  func (w *Worker) Kill() (e error) {
  65  	if e = w.Cmd.Process.Kill(); !E.Chk(e) {
  66  		D.Ln("killed")
  67  	}
  68  	return
  69  }
  70  
  71  // Stop signals the worker to shut down cleanly.
  72  //
  73  // Note that the worker must have handlers for os.Signal messages.
  74  //
  75  // It is possible and neater to put a quit method in the IPC API and use the quit channel built into the StdConn
  76  func (w *Worker) Stop() (e error) {
  77  	return w.Cmd.Process.Signal(os.Interrupt)
  78  }
  79