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:
parent
25de9de446
commit
847690583f
5 changed files with 21 additions and 8 deletions
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"},
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue