Skip to content

Commit 952d582

Browse files
committed
Add a separate lock for pid.
Signed-off-by: Lantao Liu <[email protected]>
1 parent 9777d76 commit 952d582

3 files changed

Lines changed: 26 additions & 8 deletions

File tree

runtime/v1/linux/proc/exec.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ type execProcess struct {
4949
io runc.IO
5050
status int
5151
exited time.Time
52-
pid int
52+
pid *safePid
5353
closers []io.Closer
5454
stdin io.Closer
5555
stdio proc.Stdio
@@ -69,9 +69,7 @@ func (e *execProcess) ID() string {
6969
}
7070

7171
func (e *execProcess) Pid() int {
72-
e.mu.Lock()
73-
defer e.mu.Unlock()
74-
return e.pid
72+
return e.pid.get()
7573
}
7674

7775
func (e *execProcess) ExitStatus() int {
@@ -143,7 +141,7 @@ func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
143141
}
144142

145143
func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
146-
pid := e.pid
144+
pid := e.pid.get()
147145
if pid != 0 {
148146
if err := unix.Kill(pid, syscall.Signal(sig)); err != nil {
149147
return errors.Wrapf(checkKillError(err), "exec kill error")
@@ -168,6 +166,12 @@ func (e *execProcess) Start(ctx context.Context) error {
168166
}
169167

170168
func (e *execProcess) start(ctx context.Context) (err error) {
169+
// The reaper may receive exit signal right after
170+
// the container is started, before the e.pid is updated.
171+
// In that case, we want to block the signal handler to
172+
// access e.pid until it is updated.
173+
e.pid.Lock()
174+
defer e.pid.Unlock()
171175
var (
172176
socket *runc.Socket
173177
pidfile = filepath.Join(e.path, fmt.Sprintf("%s.pid", e.id))
@@ -227,7 +231,7 @@ func (e *execProcess) start(ctx context.Context) (err error) {
227231
if err != nil {
228232
return errors.Wrap(err, "failed to retrieve OCI runtime exec pid")
229233
}
230-
e.pid = pid
234+
e.pid.pid = pid
231235
return nil
232236
}
233237

@@ -245,11 +249,11 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
245249
e.mu.Lock()
246250
defer e.mu.Unlock()
247251
// if we don't have a pid then the exec process has just been created
248-
if e.pid == 0 {
252+
if e.pid.get() == 0 {
249253
return "created", nil
250254
}
251255
// if we have a pid and it can be signaled, the process is running
252-
if err := unix.Kill(e.pid, 0); err == nil {
256+
if err := unix.Kill(e.pid.get(), 0); err == nil {
253257
return "running", nil
254258
}
255259
// else if we have a pid but it can nolonger be signaled, it has stopped

runtime/v1/linux/proc/init.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,7 @@ func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Proce
407407
Terminal: r.Terminal,
408408
},
409409
waitBlock: make(chan struct{}),
410+
pid: &safePid{},
410411
}
411412
e.execState = &execCreatedState{p: e}
412413
return e, nil

runtime/v1/linux/proc/utils.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"io"
2424
"os"
2525
"strings"
26+
"sync"
2627
"time"
2728

2829
"github.com/containerd/containerd/errdefs"
@@ -31,6 +32,18 @@ import (
3132
"golang.org/x/sys/unix"
3233
)
3334

35+
// safePid is a thread safe wrapper for pid.
36+
type safePid struct {
37+
sync.Mutex
38+
pid int
39+
}
40+
41+
func (s *safePid) get() int {
42+
s.Lock()
43+
defer s.Unlock()
44+
return s.pid
45+
}
46+
3447
// TODO(mlaventure): move to runc package?
3548
func getLastRuntimeError(r *runc.Runc) (string, error) {
3649
if r.Log == "" {

0 commit comments

Comments
 (0)