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  }