github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/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 }