forked from containers/podman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a new service reaper package. Podman currently does not reap all child processes. The slirp4netns and rootlesskit processes are not reaped. The is not a problem for local podman since the podman process dies before the other processes and then init will reap them for us. However with podman system service it is possible that the podman process is still alive after slirp died. In this case podman has to reap it or the slirp process will be a zombie until the service is stopped. The service reaper will listen in an extra goroutine on SIGCHLD. Once it receives this signal it will try to reap all pids that were added with `AddPID()`. While I would like to just reap all children this is not possible because many parts of the code use `os/exec` with `cmd.Wait()`. If we reap before `cmd.Wait()` things can break, so reaping everything is not an option. [NO TESTS NEEDED] Fixes containers#9777 Signed-off-by: Paul Holzinger <[email protected]>
- Loading branch information
Showing
3 changed files
with
70 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
//+build linux | ||
|
||
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() { | ||
delete(s.pidMap, pid) | ||
} | ||
} | ||
s.mutex.Unlock() | ||
} | ||
} |