github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/shim/proc/exec_state.go (about)

     1  // Copyright 2018 The containerd Authors.
     2  // Copyright 2018 The gVisor Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     https://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package proc
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  
    22  	"github.com/containerd/console"
    23  )
    24  
    25  type execState interface {
    26  	Resize(console.WinSize) error
    27  	Start(context.Context) error
    28  	Delete(context.Context) error
    29  	Kill(context.Context, uint32, bool) error
    30  	SetExited(int)
    31  }
    32  
    33  type execCreatedState struct {
    34  	p *execProcess
    35  }
    36  
    37  func (s *execCreatedState) name() string {
    38  	return "created"
    39  }
    40  
    41  func (s *execCreatedState) transition(transition stateTransition) {
    42  	switch transition {
    43  	case running:
    44  		s.p.execState = &execRunningState{p: s.p}
    45  	case stopped:
    46  		s.p.execState = &execStoppedState{p: s.p}
    47  	case deleted:
    48  		s.p.execState = &deletedState{}
    49  	default:
    50  		panic(fmt.Sprintf("invalid state transition %q to %q", s.name(), transition))
    51  	}
    52  }
    53  
    54  func (s *execCreatedState) Resize(ws console.WinSize) error {
    55  	return s.p.resize(ws)
    56  }
    57  
    58  func (s *execCreatedState) Start(ctx context.Context) error {
    59  	if err := s.p.start(ctx); err != nil {
    60  		return err
    61  	}
    62  	s.transition(running)
    63  	return nil
    64  }
    65  
    66  func (s *execCreatedState) Delete(context.Context) error {
    67  	if err := s.p.delete(); err != nil {
    68  		return err
    69  	}
    70  	s.transition(deleted)
    71  	return nil
    72  }
    73  
    74  func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
    75  	return s.p.kill(ctx, sig, all)
    76  }
    77  
    78  func (s *execCreatedState) SetExited(status int) {
    79  	s.p.setExited(status)
    80  	s.transition(stopped)
    81  }
    82  
    83  type execRunningState struct {
    84  	p *execProcess
    85  }
    86  
    87  func (s *execRunningState) name() string {
    88  	return "running"
    89  }
    90  
    91  func (s *execRunningState) transition(transition stateTransition) {
    92  	switch transition {
    93  	case stopped:
    94  		s.p.execState = &execStoppedState{p: s.p}
    95  	default:
    96  		panic(fmt.Sprintf("invalid state transition %q to %q", s.name(), transition))
    97  	}
    98  }
    99  
   100  func (s *execRunningState) Resize(ws console.WinSize) error {
   101  	return s.p.resize(ws)
   102  }
   103  
   104  func (s *execRunningState) Start(context.Context) error {
   105  	return fmt.Errorf("cannot start a running process")
   106  }
   107  
   108  func (s *execRunningState) Delete(context.Context) error {
   109  	return fmt.Errorf("cannot delete a running process")
   110  }
   111  
   112  func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
   113  	return s.p.kill(ctx, sig, all)
   114  }
   115  
   116  func (s *execRunningState) SetExited(status int) {
   117  	s.p.setExited(status)
   118  	s.transition(stopped)
   119  }
   120  
   121  type execStoppedState struct {
   122  	p *execProcess
   123  }
   124  
   125  func (s *execStoppedState) name() string {
   126  	return "stopped"
   127  }
   128  
   129  func (s *execStoppedState) transition(transition stateTransition) {
   130  	switch transition {
   131  	case deleted:
   132  		s.p.execState = &deletedState{}
   133  	default:
   134  		panic(fmt.Sprintf("invalid state transition %q to %q", s.name(), transition))
   135  	}
   136  }
   137  
   138  func (s *execStoppedState) Resize(console.WinSize) error {
   139  	return fmt.Errorf("cannot resize a stopped container")
   140  }
   141  
   142  func (s *execStoppedState) Start(context.Context) error {
   143  	return fmt.Errorf("cannot start a stopped process")
   144  }
   145  
   146  func (s *execStoppedState) Delete(context.Context) error {
   147  	if err := s.p.delete(); err != nil {
   148  		return err
   149  	}
   150  	s.transition(deleted)
   151  	return nil
   152  }
   153  
   154  func (s *execStoppedState) Kill(_ context.Context, sig uint32, _ bool) error {
   155  	return handleStoppedKill(sig)
   156  }
   157  
   158  func (s *execStoppedState) SetExited(int) {
   159  	// no op
   160  }