github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 "syscall" 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 bool // set true when read deadline has been reached 29 wtimedout 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 { 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 { 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 if fd.rtimer != nil { 126 fd.rtimer.Stop() 127 fd.rtimer = nil 128 } 129 fd.rtimedout = false 130 } 131 if mode == 'w' || mode == 'r'+'w' { 132 fd.wmu.Lock() 133 defer fd.wmu.Unlock() 134 if fd.wtimer != nil { 135 fd.wtimer.Stop() 136 fd.wtimer = nil 137 } 138 fd.wtimedout = false 139 } 140 if !t.IsZero() && d > 0 { 141 // Interrupt I/O operation once timer has expired 142 if mode == 'r' || mode == 'r'+'w' { 143 var timer *time.Timer 144 timer = time.AfterFunc(d, func() { 145 fd.rmu.Lock() 146 defer fd.rmu.Unlock() 147 if fd.rtimer != timer { 148 // deadline was changed 149 return 150 } 151 fd.rtimedout = true 152 if fd.raio != nil { 153 fd.raio.Cancel() 154 } 155 }) 156 fd.rtimer = timer 157 } 158 if mode == 'w' || mode == 'r'+'w' { 159 var timer *time.Timer 160 timer = time.AfterFunc(d, func() { 161 fd.wmu.Lock() 162 defer fd.wmu.Unlock() 163 if fd.wtimer != timer { 164 // deadline was changed 165 return 166 } 167 fd.wtimedout = true 168 if fd.waio != nil { 169 fd.waio.Cancel() 170 } 171 }) 172 fd.wtimer = timer 173 } 174 } 175 if !t.IsZero() && d <= 0 { 176 // Interrupt current I/O operation 177 if mode == 'r' || mode == 'r'+'w' { 178 fd.rtimedout = true 179 if fd.raio != nil { 180 fd.raio.Cancel() 181 } 182 } 183 if mode == 'w' || mode == 'r'+'w' { 184 fd.wtimedout = true 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 } 234 235 func DupCloseOnExec(fd int) (int, string, error) { 236 nfd, err := syscall.Dup(int(fd), -1) 237 if err != nil { 238 return 0, "dup", err 239 } 240 // Plan9 has no syscall.CloseOnExec but 241 // its forkAndExecInChild closes all fds 242 // not related to the fork+exec. 243 return nfd, "", nil 244 }