github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/libcontainerd/io_windows.go (about) 1 package libcontainerd 2 3 import ( 4 "context" 5 "io" 6 "net" 7 "sync" 8 9 winio "github.com/Microsoft/go-winio" 10 "github.com/containerd/containerd/cio" 11 "github.com/pkg/errors" 12 ) 13 14 type winpipe struct { 15 sync.Mutex 16 17 ctx context.Context 18 listener net.Listener 19 readyCh chan struct{} 20 readyErr error 21 22 client net.Conn 23 } 24 25 func newWinpipe(ctx context.Context, pipe string) (*winpipe, error) { 26 l, err := winio.ListenPipe(pipe, nil) 27 if err != nil { 28 return nil, errors.Wrapf(err, "%q pipe creation failed", pipe) 29 } 30 wp := &winpipe{ 31 ctx: ctx, 32 listener: l, 33 readyCh: make(chan struct{}), 34 } 35 go func() { 36 go func() { 37 defer close(wp.readyCh) 38 defer wp.listener.Close() 39 c, err := wp.listener.Accept() 40 if err != nil { 41 wp.Lock() 42 if wp.readyErr == nil { 43 wp.readyErr = err 44 } 45 wp.Unlock() 46 return 47 } 48 wp.client = c 49 }() 50 51 select { 52 case <-wp.readyCh: 53 case <-ctx.Done(): 54 wp.Lock() 55 if wp.readyErr == nil { 56 wp.listener.Close() 57 wp.readyErr = ctx.Err() 58 } 59 wp.Unlock() 60 } 61 }() 62 63 return wp, nil 64 } 65 66 func (wp *winpipe) Read(b []byte) (int, error) { 67 select { 68 case <-wp.ctx.Done(): 69 return 0, wp.ctx.Err() 70 case <-wp.readyCh: 71 return wp.client.Read(b) 72 } 73 } 74 75 func (wp *winpipe) Write(b []byte) (int, error) { 76 select { 77 case <-wp.ctx.Done(): 78 return 0, wp.ctx.Err() 79 case <-wp.readyCh: 80 return wp.client.Write(b) 81 } 82 } 83 84 func (wp *winpipe) Close() error { 85 select { 86 case <-wp.readyCh: 87 return wp.client.Close() 88 default: 89 return nil 90 } 91 } 92 93 func newIOPipe(fifos *cio.FIFOSet) (*IOPipe, error) { 94 var ( 95 err error 96 ctx, cancel = context.WithCancel(context.Background()) 97 p io.ReadWriteCloser 98 iop = &IOPipe{ 99 Terminal: fifos.Terminal, 100 cancel: cancel, 101 config: cio.Config{ 102 Terminal: fifos.Terminal, 103 Stdin: fifos.In, 104 Stdout: fifos.Out, 105 Stderr: fifos.Err, 106 }, 107 } 108 ) 109 defer func() { 110 if err != nil { 111 cancel() 112 iop.Close() 113 } 114 }() 115 116 if fifos.In != "" { 117 if p, err = newWinpipe(ctx, fifos.In); err != nil { 118 return nil, err 119 } 120 iop.Stdin = p 121 } 122 123 if fifos.Out != "" { 124 if p, err = newWinpipe(ctx, fifos.Out); err != nil { 125 return nil, err 126 } 127 iop.Stdout = p 128 } 129 130 if fifos.Err != "" { 131 if p, err = newWinpipe(ctx, fifos.Err); err != nil { 132 return nil, err 133 } 134 iop.Stderr = p 135 } 136 137 return iop, nil 138 }