api/types/container: move StateStatus, NewStateStatus internal again

These types used to be internal to the container package, but were
moved to the API in 100102108b.

However, the `StateStatus` type is only used internally; it's used
as an intermediate type because [`container.State`] contains a sync.Mutex
field which would make copying it unsafe (see [moby@2998945]).

This moves the type and re-introduces an internal type
in the original location, effectively reverting
100102108b

[`container.State`]: 19e79906cb/container/state.go (L15-L23)
[moby@2998945]: 2998945a54

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-07-23 21:30:08 +02:00
parent 25e2b4d485
commit ec3e83a7b5
9 changed files with 50 additions and 72 deletions

View File

@@ -46,8 +46,8 @@ type State struct {
Health *Health
Removed bool `json:"-"`
stopWaiters []chan<- container.StateStatus
removeOnlyWaiters []chan<- container.StateStatus
stopWaiters []chan<- StateStatus
removeOnlyWaiters []chan<- StateStatus
// The libcontainerd reference fields are unexported to force consumers
// to access them through the getter methods with multi-valued returns
@@ -58,6 +58,26 @@ type State struct {
task libcontainerdtypes.Task
}
// StateStatus is used to return container wait results.
// Implements exec.ExitCode interface.
// This type is needed as State include a sync.Mutex field which make
// copying it unsafe.
type StateStatus struct {
exitCode int
err error
}
// ExitCode returns current exitcode for the state.
func (s StateStatus) ExitCode() int {
return s.exitCode
}
// Err returns current error for the state. Returns nil if the container had
// exited on its own.
func (s StateStatus) Err() error {
return s.err
}
// NewState creates a default state object.
func NewState() *State {
return &State{}
@@ -138,20 +158,23 @@ func (s *State) StateString() container.ContainerState {
// be nil and its ExitCode() method will return the container's exit code,
// otherwise, the results Err() method will return an error indicating why the
// wait operation failed.
func (s *State) Wait(ctx context.Context, condition container.WaitCondition) <-chan container.StateStatus {
func (s *State) Wait(ctx context.Context, condition container.WaitCondition) <-chan StateStatus {
s.Lock()
defer s.Unlock()
// Buffer so we can put status and finish even nobody receives it.
resultC := make(chan container.StateStatus, 1)
resultC := make(chan StateStatus, 1)
if s.conditionAlreadyMet(condition) {
resultC <- container.NewStateStatus(s.ExitCode(), s.Err())
resultC <- StateStatus{
exitCode: s.ExitCodeValue,
err: s.Err(),
}
return resultC
}
waitC := make(chan container.StateStatus, 1)
waitC := make(chan StateStatus, 1)
// Removal wakes up both removeOnlyWaiters and stopWaiters
// Container could be removed while still in "created" state
@@ -166,8 +189,10 @@ func (s *State) Wait(ctx context.Context, condition container.WaitCondition) <-c
select {
case <-ctx.Done():
// Context timeout or cancellation.
resultC <- container.NewStateStatus(-1, ctx.Err())
resultC <- StateStatus{
exitCode: -1,
err: ctx.Err(),
}
return
case status := <-waitC:
resultC <- status
@@ -397,8 +422,11 @@ func (s *State) Err() error {
return nil
}
func (s *State) notifyAndClear(waiters *[]chan<- container.StateStatus) {
result := container.NewStateStatus(s.ExitCodeValue, s.Err())
func (s *State) notifyAndClear(waiters *[]chan<- StateStatus) {
result := StateStatus{
exitCode: s.ExitCodeValue,
err: s.Err(),
}
for _, c := range *waiters {
c <- result