Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 38 additions & 47 deletions internal/oci/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,9 @@ type Container struct {
created bool
spoofed bool
stopping bool
stopTimeoutChan chan time.Duration
stoppedChan chan struct{}
stopStoppingChan chan struct{}
stopLock sync.Mutex
stopTimeoutChan chan int64
stopWatchers []chan struct{}
pidns nsmgr.Namespace
restore bool
restoreArchive string
Expand Down Expand Up @@ -136,21 +135,20 @@ func NewContainer(id, name, bundlePath, logPath string, labels, crioAnnotations,
},
ImageRef: imageRef,
},
name: name,
bundlePath: bundlePath,
logPath: logPath,
terminal: terminal,
stdin: stdin,
stdinOnce: stdinOnce,
runtimeHandler: runtimeHandler,
crioAnnotations: crioAnnotations,
imageName: imageName,
dir: dir,
state: state,
stopSignal: stopSignal,
stopTimeoutChan: make(chan time.Duration, 1),
stoppedChan: make(chan struct{}, 1),
stopStoppingChan: make(chan struct{}, 1),
name: name,
bundlePath: bundlePath,
logPath: logPath,
terminal: terminal,
stdin: stdin,
stdinOnce: stdinOnce,
runtimeHandler: runtimeHandler,
crioAnnotations: crioAnnotations,
imageName: imageName,
dir: dir,
state: state,
stopSignal: stopSignal,
stopTimeoutChan: make(chan int64, 10),
stopWatchers: []chan struct{}{},
}
return c, nil
}
Expand Down Expand Up @@ -499,9 +497,9 @@ func (c *Container) exitFilePath() string {
return filepath.Join(c.dir, "exit")
}

// IsAlive is a function that checks if a container's init PID exists.
// Living is a function that checks if a container's init PID exists.
// It is used to check a container state when we don't want a `$runtime state` call
func (c *Container) IsAlive() error {
func (c *Container) Living() error {
if _, err := c.pid(); err != nil {
return fmt.Errorf("checking if PID of %s is running failed: %w", c.ID(), err)
}
Expand Down Expand Up @@ -603,7 +601,7 @@ func GetPidStartTimeFromFile(file string) (string, error) {
// a container is not stoppable if it's paused or stopped
// if it's paused, that's an error, and is reported as such
func (c *Container) ShouldBeStopped() error {
switch c.state.Status {
switch c.State().Status {
case ContainerStateStopped: // no-op
return ErrContainerStopped
case ContainerStatePaused:
Expand All @@ -621,41 +619,34 @@ func (c *Container) Spoofed() bool {
}

// SetAsStopping marks a container as being stopped.
// If a stop is currently happening, it also sends the new timeout
// along the stopTimeoutChan, allowing the in-progress stop
// to stop faster, or ignore the new stop timeout.
// In this case, it also returns true, signifying the caller doesn't have to
// Do any stop related cleanup, as the original caller (alreadyStopping=false)
// will do said cleanup.
func (c *Container) SetAsStopping(timeout int64) (alreadyStopping bool) {
// First, need to check if the container is already stopping
// Returns true if the container was not set as stopping before, and false otherwise (i.e. on subsequent calls)."
func (c *Container) SetAsStopping() (setToStopping bool) {
c.stopLock.Lock()
defer c.stopLock.Unlock()
if c.stopping {
// If so, we shouldn't wait forever on the opLock.
// This can cause issues where the container stop gets DOSed by a very long
// timeout, followed a shorter one coming in.
// Instead, interrupt the other stop with this new one.
select {
case c.stopTimeoutChan <- time.Duration(timeout) * time.Second:
case <-c.stoppedChan: // This case is to avoid waiting forever once another routine has finished.
case <-c.stopStoppingChan: // This case is to avoid deadlocking with SetAsNotStopping.
}
if !c.stopping {
c.stopping = true
return true
}
// Regardless, set the container as actively stopping.
c.stopping = true
// And reset the stopStoppingChan
c.stopStoppingChan = make(chan struct{}, 1)
return false
}

// SetAsNotStopping unsets the stopping field indicating to new callers that the container
// is no longer actively stopping.
func (c *Container) SetAsNotStopping() {
func (c *Container) WaitOnStopTimeout(ctx context.Context, timeout int64) {
c.stopLock.Lock()
c.stopping = false
if !c.stopping {
c.stopLock.Unlock()
return
}

c.stopTimeoutChan <- timeout

watcher := make(chan struct{}, 1)
c.stopWatchers = append(c.stopWatchers, watcher)
c.stopLock.Unlock()

select {
case <-ctx.Done():
case <-watcher:
}
}

func (c *Container) AddManagedPIDNamespace(ns nsmgr.Namespace) {
Expand Down
8 changes: 4 additions & 4 deletions internal/oci/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,14 +461,14 @@ var _ = t.Describe("Container", func() {
Expect(err).To(BeNil())
})
})
t.Describe("IsAlive", func() {
t.Describe("Living", func() {
It("should be false if pid uninitialized", func() {
// Given
state := &oci.ContainerState{}
state.Pid = 0
sut.SetState(state)
// When
err := sut.IsAlive()
err := sut.Living()

// Then
Expect(err).NotTo(BeNil())
Expand All @@ -480,7 +480,7 @@ var _ = t.Describe("Container", func() {
Expect(state.SetInitPid(state.Pid)).To(BeNil())
sut.SetState(state)
// When
err := sut.IsAlive()
err := sut.Living()

// Then
Expect(err).To(BeNil())
Expand All @@ -493,7 +493,7 @@ var _ = t.Describe("Container", func() {
Expect(state.SetInitPid(state.Pid)).NotTo(BeNil())
sut.SetState(state)
// When
err := sut.IsAlive()
err := sut.Living()

// Then
Expect(err).NotTo(BeNil())
Expand Down
18 changes: 18 additions & 0 deletions internal/oci/container_test_inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

package oci

import (
"github.com/cri-o/cri-o/pkg/config"
)

// SetState sets the container state
func (c *Container) SetState(state *ContainerState) {
c.state = state
Expand All @@ -24,3 +28,17 @@ func (c *Container) SetStateAndSpoofPid(state *ContainerState) {
}
c.state = state
}

type RuntimeOCI struct {
*runtimeOCI
}

func NewRuntimeOCI(r *Runtime, handler *config.RuntimeHandler) RuntimeOCI {
return RuntimeOCI{
runtimeOCI: &runtimeOCI{
Runtime: r,
root: handler.RuntimeRoot,
handler: handler,
},
}
}
Loading