github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 // Read implements io.Reader. 54 func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) { 55 if fd.rtimedout.isSet() { 56 return 0, ErrTimeout 57 } 58 if err := fd.readLock(); err != nil { 59 return 0, err 60 } 61 defer fd.readUnlock() 62 if len(b) == 0 { 63 return 0, nil 64 } 65 fd.raio = newAsyncIO(fn, b) 66 n, err := fd.raio.Wait() 67 fd.raio = nil 68 if isHangup(err) { 69 err = io.EOF 70 } 71 if isInterrupted(err) { 72 err = ErrTimeout 73 } 74 return n, err 75 } 76 77 // Write implements io.Writer. 78 func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) { 79 if fd.wtimedout.isSet() { 80 return 0, ErrTimeout 81 } 82 if err := fd.writeLock(); err != nil { 83 return 0, err 84 } 85 defer fd.writeUnlock() 86 fd.waio = newAsyncIO(fn, b) 87 n, err := fd.waio.Wait() 88 fd.waio = nil 89 if isInterrupted(err) { 90 err = ErrTimeout 91 } 92 return n, err 93 } 94 95 // SetDeadline sets the read and write deadlines associated with fd. 96 func (fd *FD) SetDeadline(t time.Time) error { 97 return setDeadlineImpl(fd, t, 'r'+'w') 98 } 99 100 // SetReadDeadline sets the read deadline associated with fd. 101 func (fd *FD) SetReadDeadline(t time.Time) error { 102 return setDeadlineImpl(fd, t, 'r') 103 } 104 105 // SetWriteDeadline sets the write deadline associated with fd. 106 func (fd *FD) SetWriteDeadline(t time.Time) error { 107 return setDeadlineImpl(fd, t, 'w') 108 } 109 110 func setDeadlineImpl(fd *FD, t time.Time, mode int) error { 111 d := t.Sub(time.Now()) 112 if mode == 'r' || mode == 'r'+'w' { 113 fd.rtimedout.setFalse() 114 } 115 if mode == 'w' || mode == 'r'+'w' { 116 fd.wtimedout.setFalse() 117 } 118 if t.IsZero() || d < 0 { 119 // Stop timer 120 if mode == 'r' || mode == 'r'+'w' { 121 if fd.rtimer != nil { 122 fd.rtimer.Stop() 123 } 124 fd.rtimer = nil 125 } 126 if mode == 'w' || mode == 'r'+'w' { 127 if fd.wtimer != nil { 128 fd.wtimer.Stop() 129 } 130 fd.wtimer = nil 131 } 132 } else { 133 // Interrupt I/O operation once timer has expired 134 if mode == 'r' || mode == 'r'+'w' { 135 fd.rtimer = time.AfterFunc(d, func() { 136 fd.rtimedout.setTrue() 137 if fd.raio != nil { 138 fd.raio.Cancel() 139 } 140 }) 141 } 142 if mode == 'w' || mode == 'r'+'w' { 143 fd.wtimer = time.AfterFunc(d, func() { 144 fd.wtimedout.setTrue() 145 if fd.waio != nil { 146 fd.waio.Cancel() 147 } 148 }) 149 } 150 } 151 if !t.IsZero() && d < 0 { 152 // Interrupt current I/O operation 153 if mode == 'r' || mode == 'r'+'w' { 154 fd.rtimedout.setTrue() 155 if fd.raio != nil { 156 fd.raio.Cancel() 157 } 158 } 159 if mode == 'w' || mode == 'r'+'w' { 160 fd.wtimedout.setTrue() 161 if fd.waio != nil { 162 fd.waio.Cancel() 163 } 164 } 165 } 166 return nil 167 } 168 169 // On Plan 9 only, expose the locking for the net code. 170 171 // ReadLock wraps FD.readLock. 172 func (fd *FD) ReadLock() error { 173 return fd.readLock() 174 } 175 176 // ReadUnlock wraps FD.readUnlock. 177 func (fd *FD) ReadUnlock() { 178 fd.readUnlock() 179 } 180 181 func isHangup(err error) bool { 182 return err != nil && stringsHasSuffix(err.Error(), "Hangup") 183 } 184 185 func isInterrupted(err error) bool { 186 return err != nil && stringsHasSuffix(err.Error(), "interrupted") 187 } 188 189 // PollDescriptor returns the descriptor being used by the poller, 190 // or ^uintptr(0) if there isn't one. This is only used for testing. 191 func PollDescriptor() uintptr { 192 return ^uintptr(0) 193 }