Skip to content

Commit

Permalink
innermost child
Browse files Browse the repository at this point in the history
  • Loading branch information
tamird committed Oct 18, 2024
1 parent 897520f commit d365205
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,6 @@ jobs:
with:
go-version: stable
- run: go run main.go ${{ github.workspace }} ${{ matrix.program }}

- uses: mxschmitt/action-tmate@v3
if: ${{ failure() }}
2 changes: 1 addition & 1 deletion cargo-generate.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[template]
cargo_generate_version = ">=0.10.0"
ignore = [".github", "test.py"]
ignore = [".github", "main.go"]

[placeholders.program_type]
type = "string"
Expand Down
71 changes: 62 additions & 9 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (
"os/exec"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
"time"
)

Expand Down Expand Up @@ -157,9 +157,9 @@ func run() error {
cmd.Env = cmdSpec.Env
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Printf("%+v\n", cmdSpec)
fmt.Printf("%#v\n", cmdSpec)
if err := cmd.Run(); err != nil {
return fmt.Errorf("%+v failed: %w", cmdSpec, err)
return fmt.Errorf("%#v failed: %w", cmdSpec, err)
}
}

Expand All @@ -170,11 +170,6 @@ func run() error {
cmd := exec.CommandContext(ctx, "cargo", "xtask", "run")
cmd.Dir = projectDir
cmd.Stderr = os.Stderr
// Prevent the child process from being in our process group so that we can send it a SIGINT
// without sending one to ourselves.
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}

stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
Expand All @@ -192,8 +187,24 @@ func run() error {
if _, err := fmt.Fprintln(os.Stdout, text); err != nil {
panic(err)
}

if strings.Contains(text, "Waiting for Ctrl-C") {
syscall.Kill(-cmd.Process.Pid, syscall.SIGINT)
var processes []*os.Process
for process, err := range children(cmd.Process) {
if err != nil {
return err
}
processes = append(processes, process)
}
for i := len(processes) - 1; i >= 0; i-- {
process := processes[i]
fmt.Printf("Sending SIGINT to child pid %d\n", process.Pid)
if err := process.Signal(os.Interrupt); err != nil {
if _, err := fmt.Fprintf(os.Stderr, "failed to interrupt %d: %s", process, err); err != nil {
panic(err)
}
}
}
}
}
if err := scanner.Err(); err != nil {
Expand All @@ -207,3 +218,45 @@ func run() error {

return nil
}

func children(process *os.Process) func(func(*os.Process, error) bool) {
return func(yield func(*os.Process, error) bool) {
taskPath := fmt.Sprintf("/proc/%d/task", process.Pid)
entries, err := os.ReadDir(taskPath)
if err != nil {
yield(nil, fmt.Errorf("failed to readdir %s: %w", taskPath, err))
return
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
childrenPath := fmt.Sprintf("%s/%s/children", taskPath, entry.Name())
childrenContent, err := os.ReadFile(childrenPath)
if err != nil {
yield(nil, fmt.Errorf("failed to read %s: %w", childrenPath, err))
return
}
for _, childField := range strings.Fields(string(childrenContent)) {
childPid, err := strconv.Atoi(childField)
if err != nil {
yield(nil, fmt.Errorf("failed to parse %s: %w", childField, err))
return
}
child, err := os.FindProcess(childPid)
if err != nil {
yield(nil, fmt.Errorf("failed to find process %d: %w", childPid, err))
return
}
for process, err := range children(child) {
if !yield(process, err) {
return
}
}
}
}
if !yield(process, nil) {
return
}
}
}

0 comments on commit d365205

Please sign in to comment.