linux: Prevent deadlock in reaper.WaitPid()

A deadlock can occurs if `WaitPid()` is called twice before the process
dies.

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
This commit is contained in:
Kenfe-Mickael Laventure 2017-08-14 14:26:00 -07:00
parent 9923a49e97
commit eb4abac9f7
No known key found for this signature in database
GPG Key ID: 40CF16616B361216
2 changed files with 20 additions and 14 deletions

View File

@ -88,7 +88,7 @@ func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (*sh
s.processes[r.ID] = process
s.mu.Unlock()
cmd := &reaper.Cmd{
ExitCh: make(chan int, 1),
ExitCh: make(chan struct{}),
}
reaper.Default.Register(pid, cmd)
s.events <- &eventsapi.TaskCreate{
@ -126,7 +126,7 @@ func (s *Service) Start(ctx context.Context, r *shimapi.StartRequest) (*shimapi.
} else {
pid := p.Pid()
cmd := &reaper.Cmd{
ExitCh: make(chan int, 1),
ExitCh: make(chan struct{}),
}
reaper.Default.Register(pid, cmd)
go s.waitExit(p, pid, cmd)
@ -366,7 +366,7 @@ func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*go
}
func (s *Service) waitExit(p process, pid int, cmd *reaper.Cmd) {
status := <-cmd.ExitCh
status, _ := reaper.Default.WaitPid(pid)
p.SetExited(status)
reaper.Default.Delete(pid)

View File

@ -4,7 +4,6 @@ package reaper
import (
"bytes"
"fmt"
"os/exec"
"sync"
@ -12,6 +11,10 @@ import (
"github.com/pkg/errors"
)
var (
ErrNoSuchProcess = errors.New("no such process")
)
// Reap should be called when the process receives an SIGCHLD. Reap will reap
// all exited processes and close their wait channels
func Reap() error {
@ -30,7 +33,8 @@ func Reap() error {
// pipes are closed and finalizers are run on the process
c.c.Wait()
}
c.ExitCh <- e.Status
c.exitStatus = e.Status
close(c.ExitCh)
}
return err
}
@ -68,7 +72,7 @@ func (m *Monitor) CombinedOutput(c *exec.Cmd) ([]byte, error) {
func (m *Monitor) Start(c *exec.Cmd) error {
rc := &Cmd{
c: c,
ExitCh: make(chan int, 1),
ExitCh: make(chan struct{}),
}
// start the process
m.Lock()
@ -105,7 +109,8 @@ func (m *Monitor) RegisterNL(pid int, c *Cmd) {
if status, ok := m.unknown[pid]; ok {
delete(m.unknown, pid)
m.cmds[pid] = c
c.ExitCh <- status
c.exitStatus = status
close(c.ExitCh)
return
}
m.cmds[pid] = c
@ -116,13 +121,13 @@ func (m *Monitor) WaitPid(pid int) (int, error) {
rc, ok := m.cmds[pid]
m.Unlock()
if !ok {
return 255, fmt.Errorf("process does not exist")
return 255, errors.Wrapf(ErrNoSuchProcess, "pid %d", pid)
}
ec := <-rc.ExitCh
if ec != 0 {
return ec, errors.Errorf("exit status %d", ec)
<-rc.ExitCh
if rc.exitStatus != 0 {
return rc.exitStatus, errors.Errorf("exit status %d", rc.exitStatus)
}
return ec, nil
return rc.exitStatus, nil
}
// Command returns the registered pid for the command created
@ -140,5 +145,6 @@ func (m *Monitor) Delete(pid int) {
type Cmd struct {
c *exec.Cmd
ExitCh chan int
ExitCh chan struct{}
exitStatus int
}