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