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