|
@@ -0,0 +1,116 @@
|
|
|
+// +build go1.12
|
|
|
+
|
|
|
+/*
|
|
|
+ Copyright The containerd Authors.
|
|
|
+
|
|
|
+ Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
+ you may not use this file except in compliance with the License.
|
|
|
+ You may obtain a copy of the License at
|
|
|
+
|
|
|
+ http://www.apache.org/licenses/LICENSE-2.0
|
|
|
+
|
|
|
+ Unless required by applicable law or agreed to in writing, software
|
|
|
+ distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
+ See the License for the specific language governing permissions and
|
|
|
+ limitations under the License.
|
|
|
+*/
|
|
|
+
|
|
|
+package fifo
|
|
|
+
|
|
|
+import (
|
|
|
+ "syscall"
|
|
|
+
|
|
|
+ "github.com/pkg/errors"
|
|
|
+)
|
|
|
+
|
|
|
+// SyscallConn provides raw access to the fifo's underlying filedescrptor.
|
|
|
+// See syscall.Conn for guarentees provided by this interface.
|
|
|
+func (f *fifo) SyscallConn() (syscall.RawConn, error) {
|
|
|
+ // deterministic check for closed
|
|
|
+ select {
|
|
|
+ case <-f.closed:
|
|
|
+ return nil, errors.New("fifo closed")
|
|
|
+ default:
|
|
|
+ }
|
|
|
+
|
|
|
+ select {
|
|
|
+ case <-f.closed:
|
|
|
+ return nil, errors.New("fifo closed")
|
|
|
+ case <-f.opened:
|
|
|
+ return f.file.SyscallConn()
|
|
|
+ default:
|
|
|
+ }
|
|
|
+
|
|
|
+ // Not opened and not closed, this means open is non-blocking AND it's not open yet
|
|
|
+ // Use rawConn to deal with non-blocking open.
|
|
|
+ rc := &rawConn{f: f, ready: make(chan struct{})}
|
|
|
+ go func() {
|
|
|
+ select {
|
|
|
+ case <-f.closed:
|
|
|
+ return
|
|
|
+ case <-f.opened:
|
|
|
+ rc.raw, rc.err = f.file.SyscallConn()
|
|
|
+ close(rc.ready)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ return rc, nil
|
|
|
+}
|
|
|
+
|
|
|
+type rawConn struct {
|
|
|
+ f *fifo
|
|
|
+ ready chan struct{}
|
|
|
+ raw syscall.RawConn
|
|
|
+ err error
|
|
|
+}
|
|
|
+
|
|
|
+func (r *rawConn) Control(f func(fd uintptr)) error {
|
|
|
+ select {
|
|
|
+ case <-r.f.closed:
|
|
|
+ return errors.New("control of closed fifo")
|
|
|
+ case <-r.ready:
|
|
|
+ }
|
|
|
+
|
|
|
+ if r.err != nil {
|
|
|
+ return r.err
|
|
|
+ }
|
|
|
+
|
|
|
+ return r.raw.Control(f)
|
|
|
+}
|
|
|
+
|
|
|
+func (r *rawConn) Read(f func(fd uintptr) (done bool)) error {
|
|
|
+ if r.f.flag&syscall.O_WRONLY > 0 {
|
|
|
+ return errors.New("reading from write-only fifo")
|
|
|
+ }
|
|
|
+
|
|
|
+ select {
|
|
|
+ case <-r.f.closed:
|
|
|
+ return errors.New("reading of a closed fifo")
|
|
|
+ case <-r.ready:
|
|
|
+ }
|
|
|
+
|
|
|
+ if r.err != nil {
|
|
|
+ return r.err
|
|
|
+ }
|
|
|
+
|
|
|
+ return r.raw.Read(f)
|
|
|
+}
|
|
|
+
|
|
|
+func (r *rawConn) Write(f func(fd uintptr) (done bool)) error {
|
|
|
+ if r.f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 {
|
|
|
+ return errors.New("writing to read-only fifo")
|
|
|
+ }
|
|
|
+
|
|
|
+ select {
|
|
|
+ case <-r.f.closed:
|
|
|
+ return errors.New("writing to a closed fifo")
|
|
|
+ case <-r.ready:
|
|
|
+ }
|
|
|
+
|
|
|
+ if r.err != nil {
|
|
|
+ return r.err
|
|
|
+ }
|
|
|
+
|
|
|
+ return r.raw.Write(f)
|
|
|
+}
|