mirror of
https://github.com/rancher/os.git
synced 2025-07-04 10:36:14 +00:00
107 lines
1.6 KiB
Go
107 lines
1.6 KiB
Go
package subreaper
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/containerd/osutils"
|
|
)
|
|
|
|
var (
|
|
subscriptions = map[int]*Subscription{}
|
|
subLock = sync.Mutex{}
|
|
counter = 0
|
|
once = sync.Once{}
|
|
)
|
|
|
|
type Subscription struct {
|
|
id int
|
|
exit osutils.Exit
|
|
c chan osutils.Exit
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
func (s *Subscription) SetPid(pid int) {
|
|
go func() {
|
|
for exit := range s.c {
|
|
if exit.Pid == pid {
|
|
s.exit = exit
|
|
s.wg.Done()
|
|
Unsubscribe(s)
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (s *Subscription) Wait() int {
|
|
s.wg.Wait()
|
|
return s.exit.Status
|
|
}
|
|
|
|
func Subscribe() *Subscription {
|
|
subLock.Lock()
|
|
defer subLock.Unlock()
|
|
|
|
Start()
|
|
|
|
counter++
|
|
s := &Subscription{
|
|
id: counter,
|
|
c: make(chan osutils.Exit, 1024),
|
|
}
|
|
s.wg.Add(1)
|
|
subscriptions[s.id] = s
|
|
return s
|
|
}
|
|
|
|
func Unsubscribe(sub *Subscription) {
|
|
subLock.Lock()
|
|
defer subLock.Unlock()
|
|
|
|
if _, ok := subscriptions[sub.id]; ok {
|
|
close(sub.c)
|
|
delete(subscriptions, sub.id)
|
|
}
|
|
}
|
|
|
|
func Start() error {
|
|
var err error
|
|
once.Do(func() {
|
|
err = osutils.SetSubreaper(1)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
s := make(chan os.Signal, 2048)
|
|
signal.Notify(s, syscall.SIGCHLD)
|
|
go childReaper(s)
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func childReaper(s chan os.Signal) {
|
|
for range s {
|
|
exits, err := osutils.Reap()
|
|
if err == nil {
|
|
notify(exits)
|
|
} else {
|
|
logrus.WithField("error", err).Warn("containerd: reap child processes")
|
|
}
|
|
}
|
|
}
|
|
|
|
func notify(exits []osutils.Exit) {
|
|
subLock.Lock()
|
|
for _, exit := range exits {
|
|
for _, sub := range subscriptions {
|
|
sub.c <- exit
|
|
}
|
|
}
|
|
subLock.Unlock()
|
|
}
|