code: func (p *execProcess) TerminateNicely(killGracePeriod time.Duration) error {
  	// Make sure process is being waited on for process state reaping to occur
  	// as to avoid forcibly killing the process after killGracePeriod
  	if p.waitCh == nil {
  		panic("TerminateNicely() must be called after Wait()")
  	}
  
  	err := p.signalGroup(syscall.SIGTERM)
  	if err != nil {
  		return bosherr.WrapErrorf(err, "Sending SIGTERM to process group %d", p.pgid)
  	}
  
  	terminatedCh := make(chan struct{})
  	stopCheckingTerminatedCh := make(chan struct{})
  
  	go func() {
  		for p.groupExists() {
  			select {
  			case <-time.After(500 * time.Millisecond):
  				// nothing to do
  			case <-stopCheckingTerminatedCh:
  				return
  			}
  		}
  
  		close(terminatedCh)
  	}()
  
  	select {
  	case <-terminatedCh:
  		// nothing to do
  
  	case <-time.After(killGracePeriod):
  		close(stopCheckingTerminatedCh)
  
  		err = p.signalGroup(syscall.SIGKILL)
  		if err != nil {
  			return bosherr.WrapErrorf(err, "Sending SIGKILL to process group %d", p.pgid)
  		}
  	}
  
  	// It takes some time for the process to disappear
  	for i := 0; i < 20; i++ {
  		if !p.groupExists() {
  			return nil
  		}
  		time.Sleep(500 * time.Millisecond)
  	}
  
  	return bosherr.Errorf("Failed to kill process after grace timeout (PID %d)", p.pid)
  }
docs: // TerminateNicely can be called multiple times simultaneously from different goroutines