github.com/demonoid81/containerd@v1.3.4/runtime/v2/runc/platform.go (about)

     1  // +build linux
     2  
     3  /*
     4     Copyright The containerd Authors.
     5  
     6     Licensed under the Apache License, Version 2.0 (the "License");
     7     you may not use this file except in compliance with the License.
     8     You may obtain a copy of the License at
     9  
    10         http://www.apache.org/licenses/LICENSE-2.0
    11  
    12     Unless required by applicable law or agreed to in writing, software
    13     distributed under the License is distributed on an "AS IS" BASIS,
    14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15     See the License for the specific language governing permissions and
    16     limitations under the License.
    17  */
    18  
    19  package runc
    20  
    21  import (
    22  	"context"
    23  	"io"
    24  	"sync"
    25  	"syscall"
    26  
    27  	"github.com/containerd/console"
    28  	"github.com/containerd/containerd/pkg/stdio"
    29  	"github.com/containerd/fifo"
    30  	"github.com/pkg/errors"
    31  )
    32  
    33  var bufPool = sync.Pool{
    34  	New: func() interface{} {
    35  		// setting to 4096 to align with PIPE_BUF
    36  		// http://man7.org/linux/man-pages/man7/pipe.7.html
    37  		buffer := make([]byte, 4096)
    38  		return &buffer
    39  	},
    40  }
    41  
    42  // NewPlatform returns a linux platform for use with I/O operations
    43  func NewPlatform() (stdio.Platform, error) {
    44  	epoller, err := console.NewEpoller()
    45  	if err != nil {
    46  		return nil, errors.Wrap(err, "failed to initialize epoller")
    47  	}
    48  	go epoller.Wait()
    49  	return &linuxPlatform{
    50  		epoller: epoller,
    51  	}, nil
    52  }
    53  
    54  type linuxPlatform struct {
    55  	epoller *console.Epoller
    56  }
    57  
    58  func (p *linuxPlatform) CopyConsole(ctx context.Context, console console.Console, stdin, stdout, stderr string, wg *sync.WaitGroup) (console.Console, error) {
    59  	if p.epoller == nil {
    60  		return nil, errors.New("uninitialized epoller")
    61  	}
    62  
    63  	epollConsole, err := p.epoller.Add(console)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	var cwg sync.WaitGroup
    69  	if stdin != "" {
    70  		in, err := fifo.OpenFifo(context.Background(), stdin, syscall.O_RDONLY|syscall.O_NONBLOCK, 0)
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  		cwg.Add(1)
    75  		go func() {
    76  			cwg.Done()
    77  			bp := bufPool.Get().(*[]byte)
    78  			defer bufPool.Put(bp)
    79  			io.CopyBuffer(epollConsole, in, *bp)
    80  			// we need to shutdown epollConsole when pipe broken
    81  			epollConsole.Shutdown(p.epoller.CloseConsole)
    82  			epollConsole.Close()
    83  		}()
    84  	}
    85  
    86  	outw, err := fifo.OpenFifo(ctx, stdout, syscall.O_WRONLY, 0)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	outr, err := fifo.OpenFifo(ctx, stdout, syscall.O_RDONLY, 0)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	wg.Add(1)
    95  	cwg.Add(1)
    96  	go func() {
    97  		cwg.Done()
    98  		buf := bufPool.Get().(*[]byte)
    99  		defer bufPool.Put(buf)
   100  		io.CopyBuffer(outw, epollConsole, *buf)
   101  
   102  		outw.Close()
   103  		outr.Close()
   104  		wg.Done()
   105  	}()
   106  	cwg.Wait()
   107  	return epollConsole, nil
   108  }
   109  
   110  func (p *linuxPlatform) ShutdownConsole(ctx context.Context, cons console.Console) error {
   111  	if p.epoller == nil {
   112  		return errors.New("uninitialized epoller")
   113  	}
   114  	epollConsole, ok := cons.(*console.EpollConsole)
   115  	if !ok {
   116  		return errors.Errorf("expected EpollConsole, got %#v", cons)
   117  	}
   118  	return epollConsole.Shutdown(p.epoller.CloseConsole)
   119  }
   120  
   121  func (p *linuxPlatform) Close() error {
   122  	return p.epoller.Close()
   123  }