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