func (e *Execution) Wait() {
	<-e.Done
	e.channel.Wait()
	e.inProcess.Wait()
}
Wait waits for all aspects of this execution to finish. This should happen
soon after shutdown is called.

Note that while it is a bug for this to take more than some seconds, the
method isn't needed in normal operation - it exists primarily for tests to
ensure that resources are not leaked.
package execution
import (
	"context"
	"errors"
	"flag"
	"fmt"
	"os"
	"os/exec"
	"sync"
	"sync/atomic"
	"time"
	log "github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes"
	"github.com/google/fleetspeak/fleetspeak/src/client/channel"
	"github.com/google/fleetspeak/fleetspeak/src/client/daemonservice/command"
	"github.com/google/fleetspeak/fleetspeak/src/client/internal/monitoring"
	intprocess "github.com/google/fleetspeak/fleetspeak/src/client/internal/process"
	"github.com/google/fleetspeak/fleetspeak/src/client/service"
	fcpb "github.com/google/fleetspeak/fleetspeak/src/client/channel/proto/fleetspeak_channel"
	dspb "github.com/google/fleetspeak/fleetspeak/src/client/daemonservice/proto/fleetspeak_daemonservice"
	fspb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak"
	mpb "github.com/google/fleetspeak/fleetspeak/src/common/proto/fleetspeak_monitoring"
)
const (
	maxFlushBytes           = 1 << 20  
	defaultFlushTimeSeconds = int32(60)
)
var (
	ErrShuttingDown = errors.New("shutting down")
	stdForward = flag.Bool("std_forward", false,
		"If set attaches the dependent service to the client's stdin, stdout, stderr. Meant for testing individual daemonservice integrations.")
	startupDataTimeout = 10 * time.Second
)
type atomicString struct {
	v atomic.Value
}
func (s *atomicString) Set(val string) {
	s.v.Store(val)
}
func (s *atomicString) Get() string {
	stored := s.v.Load()
	if stored == nil {
		return ""
	}
	return stored.(string)
}
type atomicBool struct {
	v atomic.Value
}
func (b *atomicBool) Set(val bool) {
	b.v.Store(val)
}
func (b *atomicBool) Get() bool {
	stored := b.v.Load()
	if stored == nil {
		return false
	}
	return stored.(bool)
}
type atomicTime struct {
	v atomic.Value
}
func (t *atomicTime) Set(val time.Time) {
	t.v.Store(val)
}
func (t *atomicTime) Get() time.Time {
	stored := t.v.Load()
	if stored == nil {
		return time.Unix(0, 0).UTC()
	}
	return stored.(time.Time)
}
type Execution struct {
	daemonServiceName string
	memoryLimit       int64
	samplePeriod      time.Duration
	sampleSize        int
	Done chan struct{}         
	Out  chan<- *fspb.Message  
	sc        service.Context
	channel   *channel.Channel
	cmd       *command.Command
	StartTime time.Time
	outData        *dspb.StdOutputData  
	lastOut        time.Time            
	outLock        sync.Mutex           
	outFlushBytes  int                  
	outServiceName string               
	shutdown   sync.Once
	lastActive int64  
	dead       chan struct{}  
	waitResult error          
	inProcess   sync.WaitGroup          
	startupData chan *fcpb.StartupData  
	heartbeat                    atomicTime    
	monitorHeartbeats            bool          
	initialHeartbeatDeadlineSecs int           
	heartbeatDeadlineSecs        int           
	sending                      atomicBool    
	serviceVersion               atomicString  
}
func New(daemonServiceName string, cfg *dspb.Config, sc service.Context) (*Execution, error) {
	cfg = proto.Clone(cfg).(*dspb.Config)
	ret := Execution{
		daemonServiceName: daemonServiceName,
		memoryLimit:       cfg.MemoryLimit,
		sampleSize:        int(cfg.ResourceMonitoringSampleSize),
		samplePeriod:      time.Duration(cfg.ResourceMonitoringSamplePeriodSeconds) * time.Second,
		Done: make(chan struct{}),
		sc:        sc,
		cmd:       &command.Command{Cmd: *exec.Command(cfg.Argv[0], cfg.Argv[1:]...)},
		StartTime: time.Now(),
		outData: &dspb.StdOutputData{},
		lastOut: time.Now(),
		dead:        make(chan struct{}),
		startupData: make(chan *fcpb.StartupData, 1),
		monitorHeartbeats:            cfg.MonitorHeartbeats,
		initialHeartbeatDeadlineSecs: int(cfg.HeartbeatUnresponsiveGracePeriodSeconds),
		heartbeatDeadlineSecs:        int(cfg.HeartbeatUnresponsiveKillPeriodSeconds),
	}
	var err error
	ret.channel, err = ret.cmd.SetupCommsChannel()
	if err != nil {
		return nil, fmt.Errorf("failed to setup a comms channel: %v", err)
	}
	ret.Out = ret.channel.Out
	if cfg.StdParams != nil && cfg.StdParams.ServiceName == "" {
		log.Errorf("std_params is set, but service_name is empty. Ignoring std_params: %v", cfg.StdParams)
		cfg.StdParams = nil
	}
	if *stdForward {
		log.Warningf("std_forward is set, connecting std... to %s", cfg.Argv[0])
		ret.cmd.Stdin = os.Stdin
		ret.cmd.Stdout = os.Stdout
		ret.cmd.Stderr = os.Stderr
	} else if cfg.StdParams != nil {
		if cfg.StdParams.FlushBytes <= 0 || cfg.StdParams.FlushBytes > maxFlushBytes {
			cfg.StdParams.FlushBytes = maxFlushBytes
		}
		if cfg.StdParams.FlushTimeSeconds <= 0 {
			cfg.StdParams.FlushTimeSeconds = defaultFlushTimeSeconds
		}
		ret.outServiceName = cfg.StdParams.ServiceName
		ret.outFlushBytes = int(cfg.StdParams.FlushBytes)
		ret.cmd.Stdout = stdoutWriter{&ret}
		ret.cmd.Stderr = stderrWriter{&ret}
	} else {
		ret.cmd.Stdout = nil
		ret.cmd.Stderr = nil
	}
	if err := ret.cmd.Start(); err != nil {
		close(ret.Done)
		return nil, err
	}
	if cfg.StdParams != nil {
		ret.inProcess.Add(1)
		go ret.stdFlushRoutine(time.Second * time.Duration(cfg.StdParams.FlushTimeSeconds))
	}
	ret.inProcess.Add(2)
	go ret.inRoutine()
	if !cfg.DisableResourceMonitoring {
		ret.inProcess.Add(1)
		go ret.statsRoutine()
	}
	go func() {
		defer func() {
			ret.Shutdown()
			ret.inProcess.Done()
		}()
		ret.waitResult = ret.cmd.Wait()
		close(ret.dead)
		if ret.waitResult != nil {
			log.Warningf("subprocess ended with error: %v", ret.waitResult)
		}
		startTime, err := ptypes.TimestampProto(ret.StartTime)
		if err != nil {
			log.Errorf("Failed to convert process start time: %v", err)
			return
		}
		if !cfg.DisableResourceMonitoring {
			rud := &mpb.ResourceUsageData{
				Scope:             ret.daemonServiceName,
				Pid:               int64(ret.cmd.Process.Pid),
				ProcessStartTime:  startTime,
				DataTimestamp:     ptypes.TimestampNow(),
				ResourceUsage:     &mpb.AggregatedResourceUsage{},
				ProcessTerminated: true,
			}
			if err := monitoring.SendProtoToServer(rud, "ResourceUsage", ret.sc); err != nil {
				log.Errorf("Failed to send final resource-usage proto: %v", err)
			}
		}
	}()
	return &ret, nil
}