nothing will be simple with reaper + os/exec in the same process
This commit is contained in:
		@ -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()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user