github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/internal/poll/fd_plan9.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package poll 6 7 import ( 8 "io" 9 "sync/atomic" 10 "time" 11 ) 12 13 type atomicBool int32 14 15 func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } 16 func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } 17 func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } 18 19 type FD struct { 20 // Lock sysfd and serialize access to Read and Write methods. 21 fdmu fdMutex 22 23 Destroy func() 24 25 // deadlines 26 raio *asyncIO 27 waio *asyncIO 28 rtimer *time.Timer 29 wtimer *time.Timer 30 rtimedout atomicBool // set true when read deadline has been reached 31 wtimedout atomicBool // set true when write deadline has been reached 32 } 33 34 // We need this to close out a file descriptor when it is unlocked, 35 // but the real implementation has to live in the net package because 36 // it uses os.File's. 37 func (fd *FD) destroy() error { 38 if fd.Destroy != nil { 39 fd.Destroy() 40 } 41 return nil 42 } 43 44 // Close handles the locking for closing an FD. The real operation 45 // is in the net package. 46 func (fd *FD) Close() error { 47 if !fd.fdmu.increfAndClose() { 48 return ErrClosing 49 } 50 return nil 51 } 52 53 func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) { 54 if fd.rtimedout.isSet() { 55 return 0, ErrTimeout 56 } 57 if err := fd.readLock(); err != nil { 58 return 0, err 59 } 60 defer fd.readUnlock() 61 if len(b) == 0 { 62 return 0, nil 63 } 64 fd.raio = newAsyncIO(fn, b) 65 n, err := fd.raio.Wait() 66 fd.raio = nil 67 if isHangup(err) { 68 err = io.EOF 69 } 70 if isInterrupted(err) { 71 err = ErrTimeout 72 } 73 return n, err 74 } 75 76 func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) { 77 if fd.wtimedout.isSet() { 78 return 0, ErrTimeout 79 } 80 if err := fd.writeLock(); err != nil { 81 return 0, err 82 } 83 defer fd.writeUnlock() 84 fd.waio = newAsyncIO(fn, b) 85 n, err := fd.waio.Wait() 86 fd.waio = nil 87 if isInterrupted(err) { 88 err = ErrTimeout 89 } 90 return n, err 91 } 92 93 func (fd *FD) SetDeadline(t time.Time) error { 94 return setDeadlineImpl(fd, t, 'r'+'w') 95 } 96 97 func (fd *FD) SetReadDeadline(t time.Time) error { 98 return setDeadlineImpl(fd, t, 'r') 99 } 100 101 func (fd *FD) SetWriteDeadline(t time.Time) error { 102 return setDeadlineImpl(fd, t, 'w') 103 } 104 105 func setDeadlineImpl(fd *FD, t time.Time, mode int) error { 106 d := t.Sub(time.Now()) 107 if mode == 'r' || mode == 'r'+'w' { 108 fd.rtimedout.setFalse() 109 } 110 if mode == 'w' || mode == 'r'+'w' { 111 fd.wtimedout.setFalse() 112 } 113 if t.IsZero() || d < 0 { 114 // Stop timer 115 if mode == 'r' || mode == 'r'+'w' { 116 if fd.rtimer != nil { 117 fd.rtimer.Stop() 118 } 119 fd.rtimer = nil 120 } 121 if mode == 'w' || mode == 'r'+'w' { 122 if fd.wtimer != nil { 123 fd.wtimer.Stop() 124 } 125 fd.wtimer = nil 126 } 127 } else { 128 // Interrupt I/O operation once timer has expired 129 if mode == 'r' || mode == 'r'+'w' { 130 fd.rtimer = time.AfterFunc(d, func() { 131 fd.rtimedout.setTrue() 132 if fd.raio != nil { 133 fd.raio.Cancel() 134 } 135 }) 136 } 137 if mode == 'w' || mode == 'r'+'w' { 138 fd.wtimer = time.AfterFunc(d, func() { 139 fd.wtimedout.setTrue() 140 if fd.waio != nil { 141 fd.waio.Cancel() 142 } 143 }) 144 } 145 } 146 if !t.IsZero() && d < 0 { 147 // Interrupt current I/O operation 148 if mode == 'r' || mode == 'r'+'w' { 149 fd.rtimedout.setTrue() 150 if fd.raio != nil { 151 fd.raio.Cancel() 152 } 153 } 154 if mode == 'w' || mode == 'r'+'w' { 155 fd.wtimedout.setTrue() 156 if fd.waio != nil { 157 fd.waio.Cancel() 158 } 159 } 160 } 161 return nil 162 } 163 164 // On Plan 9 only, expose the locking for the net code. 165 166 func (fd *FD) ReadLock() error { 167 return fd.readLock() 168 } 169 170 func (fd *FD) ReadUnlock() { 171 fd.readUnlock() 172 } 173 174 func isHangup(err error) bool { 175 return err != nil && stringsHasSuffix(err.Error(), "Hangup") 176 } 177 178 func isInterrupted(err error) bool { 179 return err != nil && stringsHasSuffix(err.Error(), "interrupted") 180 } 181 182 func PollDescriptor() uintptr { 183 return ^uintptr(0) 184 }