nothing will be simple with reaper + os/exec in the same process
This commit is contained in:
parent
ab9a10fbe3
commit
10e72f18ae
@ -1,36 +1,41 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"novit.nc/direktil/pkg/log"
|
"novit.nc/direktil/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var reapLock = sync.RWMutex{}
|
||||||
|
|
||||||
func handleChildren() {
|
func handleChildren() {
|
||||||
|
sigchld := make(chan os.Signal, 2048)
|
||||||
|
signal.Notify(sigchld, syscall.SIGCHLD)
|
||||||
|
|
||||||
// set us as a sub-reaper
|
// set us as a sub-reaper
|
||||||
if err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); err != nil {
|
if err := unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); err != nil {
|
||||||
initLog.Taintf(log.Error, "reaper: failed to set myself a child sub-reaper: %v", err)
|
initLog.Taintf(log.Error, "reaper: failed to set myself a child sub-reaper: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sigchld := make(chan os.Signal, 2048)
|
|
||||||
signal.Notify(sigchld, syscall.SIGCHLD)
|
|
||||||
|
|
||||||
for range sigchld {
|
for range sigchld {
|
||||||
reapChildren()
|
reapChildren()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reapChildren() {
|
func reapChildren() {
|
||||||
|
reapLock.Lock()
|
||||||
|
defer reapLock.Unlock()
|
||||||
for {
|
for {
|
||||||
pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil)
|
pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil)
|
||||||
if err != nil {
|
if err != nil && err != syscall.ECHILD {
|
||||||
if err == unix.ECHILD {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
initLog.Taintf(log.Warning, "reaper: wait4 failed: %v", err)
|
initLog.Taintf(log.Warning, "reaper: wait4 failed: %v", err)
|
||||||
|
fmt.Printf("reaper: wait4 failed: %v\n", err)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if pid <= 0 {
|
if pid <= 0 {
|
||||||
break
|
break
|
44
cmd/dkl-system-init/reaper_test.go
Normal file
44
cmd/dkl-system-init/reaper_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReap(t *testing.T) {
|
||||||
|
truePath, err := exec.LookPath("true")
|
||||||
|
if err != nil {
|
||||||
|
t.Log("true binary not found, ignoring this test.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go handleChildren()
|
||||||
|
|
||||||
|
count := 1000
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(count)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
i := i
|
||||||
|
go func() {
|
||||||
|
cmd := exec.Command(truePath)
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
t.Errorf("[%d] %v", i, err)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
cmd := exec.Command("sh", "-c", "ps aux |grep Z")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Run()
|
||||||
|
|
||||||
|
t.Fail()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user