reaper.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package subreaper
  2. import (
  3. "os"
  4. "os/signal"
  5. "sync"
  6. "syscall"
  7. "github.com/Sirupsen/logrus"
  8. "github.com/docker/containerd/osutils"
  9. )
  10. var (
  11. subscriptions = map[int]*Subscription{}
  12. subLock = sync.Mutex{}
  13. counter = 0
  14. once = sync.Once{}
  15. )
  16. type Subscription struct {
  17. id int
  18. exit osutils.Exit
  19. c chan osutils.Exit
  20. wg sync.WaitGroup
  21. }
  22. func (s *Subscription) SetPid(pid int) {
  23. go func() {
  24. for exit := range s.c {
  25. if exit.Pid == pid {
  26. s.exit = exit
  27. s.wg.Done()
  28. Unsubscribe(s)
  29. }
  30. }
  31. }()
  32. }
  33. func (s *Subscription) Wait() int {
  34. s.wg.Wait()
  35. return s.exit.Status
  36. }
  37. func Subscribe() *Subscription {
  38. subLock.Lock()
  39. defer subLock.Unlock()
  40. Start()
  41. counter++
  42. s := &Subscription{
  43. id: counter,
  44. c: make(chan osutils.Exit, 1024),
  45. }
  46. s.wg.Add(1)
  47. subscriptions[s.id] = s
  48. return s
  49. }
  50. func Unsubscribe(sub *Subscription) {
  51. subLock.Lock()
  52. defer subLock.Unlock()
  53. delete(subscriptions, sub.id)
  54. }
  55. func Start() error {
  56. var err error
  57. once.Do(func() {
  58. err = osutils.SetSubreaper(1)
  59. if err != nil {
  60. return
  61. }
  62. s := make(chan os.Signal, 2048)
  63. signal.Notify(s, syscall.SIGCHLD)
  64. go childReaper(s)
  65. })
  66. return err
  67. }
  68. func childReaper(s chan os.Signal) {
  69. for range s {
  70. exits, err := osutils.Reap()
  71. if err == nil {
  72. notify(exits)
  73. } else {
  74. logrus.WithField("error", err).Warn("containerd: reap child processes")
  75. }
  76. }
  77. }
  78. func notify(exits []osutils.Exit) {
  79. subLock.Lock()
  80. for _, exit := range exits {
  81. for _, sub := range subscriptions {
  82. sub.c <- exit
  83. }
  84. }
  85. subLock.Unlock()
  86. }