package hcsshim import ( "context" "io" "sync" "time" "github.com/Microsoft/hcsshim/internal/hcs" ) // ContainerError is an error encountered in HCS type process struct { p *hcs.Process waitOnce sync.Once waitCh chan struct{} waitErr error } // Pid returns the process ID of the process within the container. func (process *process) Pid() int { return process.p.Pid() } // Kill signals the process to terminate but does not wait for it to finish terminating. func (process *process) Kill() error { found, err := process.p.Kill(context.Background()) if err != nil { return convertProcessError(err, process) } if !found { return &ProcessError{Process: process, Err: ErrElementNotFound, Operation: "hcsshim::Process::Kill"} } return nil } // Wait waits for the process to exit. func (process *process) Wait() error { return convertProcessError(process.p.Wait(), process) } // WaitTimeout waits for the process to exit or the duration to elapse. It returns // false if timeout occurs. func (process *process) WaitTimeout(timeout time.Duration) error { process.waitOnce.Do(func() { process.waitCh = make(chan struct{}) go func() { process.waitErr = process.Wait() close(process.waitCh) }() }) t := time.NewTimer(timeout) defer t.Stop() select { case <-t.C: return &ProcessError{Process: process, Err: ErrTimeout, Operation: "hcsshim::Process::Wait"} case <-process.waitCh: return process.waitErr } } // ExitCode returns the exit code of the process. The process must have // already terminated. func (process *process) ExitCode() (int, error) { code, err := process.p.ExitCode() if err != nil { err = convertProcessError(err, process) } return code, err } // ResizeConsole resizes the console of the process. func (process *process) ResizeConsole(width, height uint16) error { return convertProcessError(process.p.ResizeConsole(context.Background(), width, height), process) } // Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing // these pipes does not close the underlying pipes; it should be possible to // call this multiple times to get multiple interfaces. func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) { stdin, stdout, stderr, err := process.p.StdioLegacy() if err != nil { err = convertProcessError(err, process) } return stdin, stdout, stderr, err } // CloseStdin closes the write side of the stdin pipe so that the process is // notified on the read side that there is no more data in stdin. func (process *process) CloseStdin() error { return convertProcessError(process.p.CloseStdin(context.Background()), process) } // Close cleans up any state associated with the process but does not kill // or wait on it. func (process *process) Close() error { return convertProcessError(process.p.Close(), process) }