process.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. //go:build windows
  2. package hcsshim
  3. import (
  4. "context"
  5. "io"
  6. "sync"
  7. "time"
  8. "github.com/Microsoft/hcsshim/internal/hcs"
  9. )
  10. // ContainerError is an error encountered in HCS
  11. type process struct {
  12. p *hcs.Process
  13. waitOnce sync.Once
  14. waitCh chan struct{}
  15. waitErr error
  16. }
  17. // Pid returns the process ID of the process within the container.
  18. func (process *process) Pid() int {
  19. return process.p.Pid()
  20. }
  21. // Kill signals the process to terminate but does not wait for it to finish terminating.
  22. func (process *process) Kill() error {
  23. found, err := process.p.Kill(context.Background())
  24. if err != nil {
  25. return convertProcessError(err, process)
  26. }
  27. if !found {
  28. return &ProcessError{Process: process, Err: ErrElementNotFound, Operation: "hcsshim::Process::Kill"}
  29. }
  30. return nil
  31. }
  32. // Wait waits for the process to exit.
  33. func (process *process) Wait() error {
  34. return convertProcessError(process.p.Wait(), process)
  35. }
  36. // WaitTimeout waits for the process to exit or the duration to elapse. It returns
  37. // false if timeout occurs.
  38. func (process *process) WaitTimeout(timeout time.Duration) error {
  39. process.waitOnce.Do(func() {
  40. process.waitCh = make(chan struct{})
  41. go func() {
  42. process.waitErr = process.Wait()
  43. close(process.waitCh)
  44. }()
  45. })
  46. t := time.NewTimer(timeout)
  47. defer t.Stop()
  48. select {
  49. case <-t.C:
  50. return &ProcessError{Process: process, Err: ErrTimeout, Operation: "hcsshim::Process::Wait"}
  51. case <-process.waitCh:
  52. return process.waitErr
  53. }
  54. }
  55. // ExitCode returns the exit code of the process. The process must have
  56. // already terminated.
  57. func (process *process) ExitCode() (int, error) {
  58. code, err := process.p.ExitCode()
  59. if err != nil {
  60. err = convertProcessError(err, process)
  61. }
  62. return code, err
  63. }
  64. // ResizeConsole resizes the console of the process.
  65. func (process *process) ResizeConsole(width, height uint16) error {
  66. return convertProcessError(process.p.ResizeConsole(context.Background(), width, height), process)
  67. }
  68. // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
  69. // these pipes does not close the underlying pipes; it should be possible to
  70. // call this multiple times to get multiple interfaces.
  71. func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
  72. stdin, stdout, stderr, err := process.p.StdioLegacy()
  73. if err != nil {
  74. err = convertProcessError(err, process)
  75. }
  76. return stdin, stdout, stderr, err
  77. }
  78. // CloseStdin closes the write side of the stdin pipe so that the process is
  79. // notified on the read side that there is no more data in stdin.
  80. func (process *process) CloseStdin() error {
  81. return convertProcessError(process.p.CloseStdin(context.Background()), process)
  82. }
  83. // Close cleans up any state associated with the process but does not kill
  84. // or wait on it.
  85. func (process *process) Close() error {
  86. return convertProcessError(process.p.Close(), process)
  87. }