github.com/sandwichdev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/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 "errors" 9 "io" 10 "sync" 11 "sync/atomic" 12 "time" 13 ) 14 15 type atomicBool int32 16 17 func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 } 18 func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) } 19 func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) } 20 21 type FD struct { 22 // Lock sysfd and serialize access to Read and Write methods. 23 fdmu fdMutex 24 25 Destroy func() 26 27 // deadlines 28 rmu sync.Mutex 29 wmu sync.Mutex 30 raio *asyncIO 31 waio *asyncIO 32 rtimer *time.Timer 33 wtimer *time.Timer 34 rtimedout atomicBool // set true when read deadline has been reached 35 wtimedout atomicBool // set true when write deadline has been reached 36 37 // Whether this is a normal file. 38 // On Plan 9 we do not use this package for ordinary files, 39 // so this is always false, but the field is present because 40 // shared code in fd_mutex.go checks it. 41 isFile bool 42 } 43 44 // We need this to close out a file descriptor when it is unlocked, 45 // but the real implementation has to live in the net package because 46 // it uses os.File's. 47 func (fd *FD) destroy() error { 48 if fd.Destroy != nil { 49 fd.Destroy() 50 } 51 return nil 52 } 53 54 // Close handles the locking for closing an FD. The real operation 55 // is in the net package. 56 func (fd *FD) Close() error { 57 if !fd.fdmu.increfAndClose() { 58 return errClosing(fd.isFile) 59 } 60 return nil 61 } 62 63 // Read implements io.Reader. 64 func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) { 65 if err := fd.readLock(); err != nil { 66 return 0, err 67 } 68 defer fd.readUnlock() 69 if len(b) == 0 { 70 return 0, nil 71 } 72 fd.rmu.Lock() 73 if fd.rtimedout.isSet() { 74 fd.rmu.Unlock() 75 return 0, ErrDeadlineExceeded 76 } 77 fd.raio = newAsyncIO(fn, b) 78 fd.rmu.Unlock() 79 n, err := fd.raio.Wait() 80 fd.raio = nil 81 if isHangup(err) { 82 err = io.EOF 83 } 84 if isInterrupted(err) { 85 err = ErrDeadlineExceeded 86 } 87 return n, err 88 } 89 90 // Write implements io.Writer. 91 func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) { 92 if err := fd.writeLock(); err != nil { 93 return 0, err 94 } 95 defer fd.writeUnlock() 96 fd.wmu.Lock() 97 if fd.wtimedout.isSet() { 98 fd.wmu.Unlock() 99 return 0, ErrDeadlineExceeded 100 } 101 fd.waio = newAsyncIO(fn, b) 102 fd.wmu.Unlock() 103 n, err := fd.waio.Wait() 104 fd.waio = nil 105 if isInterrupted(err) { 106 err = ErrDeadlineExceeded 107 } 108 return n, err 109 } 110 111 // SetDeadline sets the read and write deadlines associated with fd. 112 func (fd *FD) SetDeadline(t time.Time) error { 113 return setDeadlineImpl(fd, t, 'r'+'w') 114 } 115 116 // SetReadDeadline sets the read deadline associated with fd. 117 func (fd *FD) SetReadDeadline(t time.Time) error { 118 return setDeadlineImpl(fd, t, 'r') 119 } 120 121 // SetWriteDeadline sets the write deadline associated with fd. 122 func (fd *FD) SetWriteDeadline(t time.Time) error { 123 return setDeadlineImpl(fd, t, 'w') 124 } 125 126 func setDeadlineImpl(fd *FD, t time.Time, mode int) error { 127 d := t.Sub(time.Now()) 128 if mode == 'r' || mode == 'r'+'w' { 129 fd.rmu.Lock() 130 defer fd.rmu.Unlock() 131 fd.rtimedout.setFalse() 132 } 133 if mode == 'w' || mode == 'r'+'w' { 134 fd.wmu.Lock() 135 defer fd.wmu.Unlock() 136 fd.wtimedout.setFalse() 137 } 138 if t.IsZero() || d < 0 { 139 // Stop timer 140 if mode == 'r' || mode == 'r'+'w' { 141 if fd.rtimer != nil { 142 fd.rtimer.Stop() 143 } 144 fd.rtimer = nil 145 } 146 if mode == 'w' || mode == 'r'+'w' { 147 if fd.wtimer != nil { 148 fd.wtimer.Stop() 149 } 150 fd.wtimer = nil 151 } 152 } else { 153 // Interrupt I/O operation once timer has expired 154 if mode == 'r' || mode == 'r'+'w' { 155 fd.rtimer = time.AfterFunc(d, func() { 156 fd.rmu.Lock() 157 fd.rtimedout.setTrue() 158 if fd.raio != nil { 159 fd.raio.Cancel() 160 } 161 fd.rmu.Unlock() 162 }) 163 } 164 if mode == 'w' || mode == 'r'+'w' { 165 fd.wtimer = time.AfterFunc(d, func() { 166 fd.wmu.Lock() 167 fd.wtimedout.setTrue() 168 if fd.waio != nil { 169 fd.waio.Cancel() 170 } 171 fd.wmu.Unlock() 172 }) 173 } 174 } 175 if !t.IsZero() && d < 0 { 176 // Interrupt current I/O operation 177 if mode == 'r' || mode == 'r'+'w' { 178 fd.rtimedout.setTrue() 179 if fd.raio != nil { 180 fd.raio.Cancel() 181 } 182 } 183 if mode == 'w' || mode == 'r'+'w' { 184 fd.wtimedout.setTrue() 185 if fd.waio != nil { 186 fd.waio.Cancel() 187 } 188 } 189 } 190 return nil 191 } 192 193 // On Plan 9 only, expose the locking for the net code. 194 195 // ReadLock wraps FD.readLock. 196 func (fd *FD) ReadLock() error { 197 return fd.readLock() 198 } 199 200 // ReadUnlock wraps FD.readUnlock. 201 func (fd *FD) ReadUnlock() { 202 fd.readUnlock() 203 } 204 205 func isHangup(err error) bool { 206 return err != nil && stringsHasSuffix(err.Error(), "Hangup") 207 } 208 209 func isInterrupted(err error) bool { 210 return err != nil && stringsHasSuffix(err.Error(), "interrupted") 211 } 212 213 // IsPollDescriptor reports whether fd is the descriptor being used by the poller. 214 // This is only used for testing. 215 func IsPollDescriptor(fd uintptr) bool { 216 return false 217 } 218 219 // RawControl invokes the user-defined function f for a non-IO 220 // operation. 221 func (fd *FD) RawControl(f func(uintptr)) error { 222 return errors.New("not implemented") 223 } 224 225 // RawRead invokes the user-defined function f for a read operation. 226 func (fd *FD) RawRead(f func(uintptr) bool) error { 227 return errors.New("not implemented") 228 } 229 230 // RawWrite invokes the user-defined function f for a write operation. 231 func (fd *FD) RawWrite(f func(uintptr) bool) error { 232 return errors.New("not implemented") 233 }