libcontainer: Do not wait for signalled processes if subreaper is set

When a subreaper is enabled, it might expect to reap a process and
retrieve its exit code. That's the reason why this patch is giving
the possibility to define the usage of a subreaper as a consumer of
libcontainer. Relying on this information, libcontainer will not
wait for signalled processes in case a subreaper has been set.

Fixes #1677

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2017-12-14 10:12:32 -08:00
parent c6e4a1ebeb
commit bb912eb00c
2 changed files with 31 additions and 3 deletions

View File

@@ -494,6 +494,16 @@ func signalAllProcesses(m cgroups.Manager, s os.Signal) error {
logrus.Warn(err) logrus.Warn(err)
} }
subreaper, err := system.GetSubreaper()
if err != nil {
// The error here means that PR_GET_CHILD_SUBREAPER is not
// supported because this code might run on a kernel older
// than 3.4. We don't want to throw an error in that case,
// and we simplify things, considering there is no subreaper
// set.
subreaper = 0
}
for _, p := range procs { for _, p := range procs {
if s != unix.SIGKILL { if s != unix.SIGKILL {
if ok, err := isWaitable(p.Pid); err != nil { if ok, err := isWaitable(p.Pid); err != nil {
@@ -507,11 +517,18 @@ func signalAllProcesses(m cgroups.Manager, s os.Signal) error {
} }
} }
// In case a subreaper has been setup, this code must not
// wait for the process. Otherwise, we cannot be sure the
// current process will be reaped by the subreaper, while
// the subreaper might be waiting for this process in order
// to retrieve its exit code.
if subreaper == 0 {
if _, err := p.Wait(); err != nil { if _, err := p.Wait(); err != nil {
if !isNoChildren(err) { if !isNoChildren(err) {
logrus.Warn("wait: ", err) logrus.Warn("wait: ", err)
} }
} }
} }
}
return nil return nil
} }

View File

@@ -134,3 +134,14 @@ func RunningInUserNS() bool {
func SetSubreaper(i int) error { func SetSubreaper(i int) error {
return unix.Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0) return unix.Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
} }
// GetSubreaper returns the subreaper setting for the calling process
func GetSubreaper() (int, error) {
var i uintptr
if err := unix.Prctl(unix.PR_GET_CHILD_SUBREAPER, uintptr(unsafe.Pointer(&i)), 0, 0, 0); err != nil {
return -1, err
}
return int(i), nil
}