summaryrefslogtreecommitdiff
path: root/internal/io
diff options
context:
space:
mode:
authorPaul Bütow <pbuetow@mimecast.com>2020-02-16 18:07:36 +0000
committerPaul Bütow <pbuetow@mimecast.com>2020-02-16 18:07:36 +0000
commite0f4ccc46c8601f322640b72e100f973a837ef02 (patch)
tree61a1fcf66daea222da19500b0b6ae60d1e89a5d9 /internal/io
parent6bca637513e065a33cadaccad97ada25eb7a6b00 (diff)
server kills subprocesses correctly on cancel
Diffstat (limited to 'internal/io')
-rw-r--r--internal/io/run/run.go35
1 files changed, 30 insertions, 5 deletions
diff --git a/internal/io/run/run.go b/internal/io/run/run.go
index 5951cde..f9cd980 100644
--- a/internal/io/run/run.go
+++ b/internal/io/run/run.go
@@ -6,6 +6,7 @@ import (
"io"
"os/exec"
"sync"
+ "syscall"
"time"
"github.com/mimecast/dtail/internal/io/line"
@@ -14,16 +15,18 @@ import (
// Run is for execute a command.
type Run struct {
- command string
- args []string
- cmd *exec.Cmd
+ command string
+ args []string
+ cmd *exec.Cmd
+ pgroupKilled chan struct{}
}
// New returns a new command runner.
func New(command string, args []string) Run {
return Run{
- command: command,
- args: args,
+ command: command,
+ args: args,
+ pgroupKilled: make(chan struct{}),
}
}
@@ -42,6 +45,8 @@ func (r Run) Start(ctx context.Context, lines chan<- line.Line) (pid int, ec int
logger.Debug(r.command)
r.cmd = exec.CommandContext(ctx, r.command)
}
+ // Create a new process group, so that kill() will only kill this command + pgroup.
+ r.cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
stdoutPipe, myErr := r.cmd.StdoutPipe()
if err != nil {
@@ -64,6 +69,7 @@ func (r Run) Start(ctx context.Context, lines chan<- line.Line) (pid int, ec int
pid = r.cmd.Process.Pid
ec = 0
}
+ go r.killPgroup(ctx, pid)
var wg sync.WaitGroup
wg.Add(2)
@@ -103,3 +109,22 @@ func (r Run) pipeToLines(done chan struct{}, wg *sync.WaitGroup, pid int, reader
time.Sleep(time.Millisecond * 10)
}
}
+
+// PgroupKilled identifies whether all subprocesses are killed or not.
+func (r Run) PgroupKilled() <-chan struct{} {
+ return r.pgroupKilled
+}
+
+func (r Run) killPgroup(ctx context.Context, pid int) {
+ if pid == -1 {
+ close(r.pgroupKilled)
+ return
+ }
+
+ if pgid, err := syscall.Getpgid(pid); err == nil {
+ // Kill process group when done
+ <-ctx.Done()
+ syscall.Kill(-pgid, syscall.SIGKILL)
+ close(r.pgroupKilled)
+ }
+}