Remove sigchld reaper from containerd process

Because we are launching alot of different runc commands to do
operations there is a race between doing a `cmd.Wait()` and getting the
sigchld and reaping it.  We can remove the sigchild reaper from
containerd as long as we make sure we reap the shim process if we are
the parent, i.e. not restored.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2016-04-27 12:00:29 -07:00
parent 25de9de446
commit 847690583f
5 changed files with 21 additions and 8 deletions

View file

@ -134,10 +134,7 @@ func daemon(context *cli.Context) error {
// setup a standard reaper so that we don't leave any zombies if we are still alive // setup a standard reaper so that we don't leave any zombies if we are still alive
// this is just good practice because we are spawning new processes // this is just good practice because we are spawning new processes
s := make(chan os.Signal, 2048) s := make(chan os.Signal, 2048)
signal.Notify(s, syscall.SIGCHLD, syscall.SIGTERM, syscall.SIGINT) signal.Notify(s, syscall.SIGTERM, syscall.SIGINT)
if err := osutils.SetSubreaper(1); err != nil {
logrus.WithField("error", err).Error("containerd: set subpreaper")
}
sv, err := supervisor.New( sv, err := supervisor.New(
context.String("state-dir"), context.String("state-dir"),
context.String("runtime"), context.String("runtime"),
@ -169,10 +166,6 @@ func daemon(context *cli.Context) error {
} }
for ss := range s { for ss := range s {
switch ss { switch ss {
case syscall.SIGCHLD:
if _, err := osutils.Reap(); err != nil {
logrus.WithField("error", err).Warn("containerd: reap child processes")
}
default: default:
logrus.Infof("stopping containerd after receiving %s", ss) logrus.Infof("stopping containerd after receiving %s", ss)
server.Stop() server.Stop()

View file

@ -478,6 +478,7 @@ func (c *container) Exec(pid string, pspec specs.ProcessSpec, s Stdio) (pp Proce
} }
func (c *container) startCmd(pid string, cmd *exec.Cmd, p *process) error { func (c *container) startCmd(pid string, cmd *exec.Cmd, p *process) error {
p.cmd = cmd
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
if exErr, ok := err.(*exec.Error); ok { if exErr, ok := err.(*exec.Error); ok {
if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist { if exErr.Err == exec.ErrNotFound || exErr.Err == os.ErrNotExist {
@ -699,6 +700,9 @@ func (c *container) waitForStart(p *process, cmd *exec.Cmd) error {
// isAlive checks if the shim that launched the container is still alive // isAlive checks if the shim that launched the container is still alive
func isAlive(cmd *exec.Cmd) (bool, error) { func isAlive(cmd *exec.Cmd) (bool, error) {
if _, err := syscall.Wait4(cmd.Process.Pid, nil, syscall.WNOHANG, nil); err == nil {
return true, nil
}
if err := syscall.Kill(cmd.Process.Pid, 0); err != nil { if err := syscall.Kill(cmd.Process.Pid, 0); err != nil {
if err == syscall.ESRCH { if err == syscall.ESRCH {
return false, nil return false, nil

View file

@ -6,6 +6,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
"syscall" "syscall"
@ -39,6 +40,8 @@ type Process interface {
SystemPid() int SystemPid() int
// State returns if the process is running or not // State returns if the process is running or not
State() State State() State
// Wait reaps the shim process if avaliable
Wait()
} }
type processConfig struct { type processConfig struct {
@ -139,6 +142,7 @@ type process struct {
container *container container *container
spec specs.ProcessSpec spec specs.ProcessSpec
stdio Stdio stdio Stdio
cmd *exec.Cmd
} }
func (p *process) ID() string { func (p *process) ID() string {
@ -219,6 +223,13 @@ func (p *process) getPidFromFile() (int, error) {
return i, nil return i, nil
} }
// Wait will reap the shim process
func (p *process) Wait() {
if p.cmd != nil {
p.cmd.Wait()
}
}
func getExitPipe(path string) (*os.File, error) { func getExitPipe(path string) (*os.File, error) {
if err := syscall.Mkfifo(path, 0755); err != nil && !os.IsExist(err) { if err := syscall.Mkfifo(path, 0755); err != nil && !os.IsExist(err) {
return nil, err return nil, err

View file

@ -61,6 +61,10 @@ func (p *testProcess) State() runtime.State {
return runtime.Running return runtime.Running
} }
func (p *testProcess) Wait() {
}
func TestSortProcesses(t *testing.T) { func TestSortProcesses(t *testing.T) {
p := []runtime.Process{ p := []runtime.Process{
&testProcess{"ls"}, &testProcess{"ls"},

View file

@ -274,6 +274,7 @@ func (s *Supervisor) SendTask(evt Task) {
func (s *Supervisor) exitHandler() { func (s *Supervisor) exitHandler() {
for p := range s.monitor.Exits() { for p := range s.monitor.Exits() {
p.Wait()
e := &ExitTask{ e := &ExitTask{
Process: p, Process: p,
} }