github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/servicereaper/service.go (about) 1 //go:build linux 2 // +build linux 3 4 package servicereaper 5 6 import ( 7 "os" 8 "os/signal" 9 "sync" 10 "syscall" 11 12 "github.com/sirupsen/logrus" 13 ) 14 15 type service struct { 16 pidMap map[int]bool 17 mutex *sync.Mutex 18 } 19 20 var s = service{ 21 pidMap: map[int]bool{}, 22 mutex: &sync.Mutex{}, 23 } 24 25 func AddPID(pid int) { 26 s.mutex.Lock() 27 s.pidMap[pid] = true 28 s.mutex.Unlock() 29 } 30 31 func Start() { 32 // create signal channel and only wait for SIGCHLD 33 sigc := make(chan os.Signal, 1) 34 signal.Notify(sigc, syscall.SIGCHLD) 35 // wait and reap in an extra goroutine 36 go reaper(sigc) 37 } 38 39 func reaper(sigc chan os.Signal) { 40 for { 41 // block until we receive SIGCHLD 42 <-sigc 43 s.mutex.Lock() 44 for pid := range s.pidMap { 45 var status syscall.WaitStatus 46 waitpid, err := syscall.Wait4(pid, &status, syscall.WNOHANG, nil) 47 if err != nil { 48 // do not log error for ECHILD 49 if err != syscall.ECHILD { 50 logrus.Warnf("Wait for pid %d failed: %v ", pid, err) 51 } 52 delete(s.pidMap, pid) 53 continue 54 } 55 // if pid == 0 nothing happened 56 if waitpid == 0 { 57 continue 58 } 59 if status.Exited() { 60 delete(s.pidMap, pid) 61 } 62 } 63 s.mutex.Unlock() 64 } 65 }