github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/net/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 net 6 7 import ( 8 "io" 9 "os" 10 "sync/atomic" 11 "syscall" 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 // Network file descriptor. 22 type netFD struct { 23 // locking/lifetime of sysfd + serialize access to Read and Write methods 24 fdmu fdMutex 25 26 // immutable until Close 27 net string 28 n string 29 dir string 30 listen, ctl, data *os.File 31 laddr, raddr Addr 32 isStream bool 33 34 // deadlines 35 raio *asyncIO 36 waio *asyncIO 37 rtimer *time.Timer 38 wtimer *time.Timer 39 rtimedout atomicBool // set true when read deadline has been reached 40 wtimedout atomicBool // set true when write deadline has been reached 41 } 42 43 var ( 44 netdir string // default network 45 ) 46 47 func sysInit() { 48 netdir = "/net" 49 } 50 51 func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { 52 return &netFD{ 53 net: net, 54 n: name, 55 dir: netdir + "/" + net + "/" + name, 56 listen: listen, 57 ctl: ctl, data: data, 58 laddr: laddr, 59 raddr: raddr, 60 }, nil 61 } 62 63 func (fd *netFD) init() error { 64 // stub for future fd.pd.Init(fd) 65 return nil 66 } 67 68 func (fd *netFD) name() string { 69 var ls, rs string 70 if fd.laddr != nil { 71 ls = fd.laddr.String() 72 } 73 if fd.raddr != nil { 74 rs = fd.raddr.String() 75 } 76 return fd.net + ":" + ls + "->" + rs 77 } 78 79 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } 80 81 func (fd *netFD) destroy() { 82 if !fd.ok() { 83 return 84 } 85 err := fd.ctl.Close() 86 if fd.data != nil { 87 if err1 := fd.data.Close(); err1 != nil && err == nil { 88 err = err1 89 } 90 } 91 if fd.listen != nil { 92 if err1 := fd.listen.Close(); err1 != nil && err == nil { 93 err = err1 94 } 95 } 96 fd.ctl = nil 97 fd.data = nil 98 fd.listen = nil 99 } 100 101 func (fd *netFD) Read(b []byte) (n int, err error) { 102 if fd.rtimedout.isSet() { 103 return 0, errTimeout 104 } 105 if !fd.ok() || fd.data == nil { 106 return 0, syscall.EINVAL 107 } 108 if err := fd.readLock(); err != nil { 109 return 0, err 110 } 111 defer fd.readUnlock() 112 if len(b) == 0 { 113 return 0, nil 114 } 115 fd.raio = newAsyncIO(fd.data.Read, b) 116 n, err = fd.raio.Wait() 117 fd.raio = nil 118 if isHangup(err) { 119 err = io.EOF 120 } 121 if isInterrupted(err) { 122 err = errTimeout 123 } 124 if fd.net == "udp" && err == io.EOF { 125 n = 0 126 err = nil 127 } 128 return 129 } 130 131 func (fd *netFD) Write(b []byte) (n int, err error) { 132 if fd.wtimedout.isSet() { 133 return 0, errTimeout 134 } 135 if !fd.ok() || fd.data == nil { 136 return 0, syscall.EINVAL 137 } 138 if err := fd.writeLock(); err != nil { 139 return 0, err 140 } 141 defer fd.writeUnlock() 142 fd.waio = newAsyncIO(fd.data.Write, b) 143 n, err = fd.waio.Wait() 144 fd.waio = nil 145 if isInterrupted(err) { 146 err = errTimeout 147 } 148 return 149 } 150 151 func (fd *netFD) closeRead() error { 152 if !fd.ok() { 153 return syscall.EINVAL 154 } 155 return syscall.EPLAN9 156 } 157 158 func (fd *netFD) closeWrite() error { 159 if !fd.ok() { 160 return syscall.EINVAL 161 } 162 return syscall.EPLAN9 163 } 164 165 func (fd *netFD) Close() error { 166 if !fd.fdmu.increfAndClose() { 167 return errClosing 168 } 169 if !fd.ok() { 170 return syscall.EINVAL 171 } 172 if fd.net == "tcp" { 173 // The following line is required to unblock Reads. 174 _, err := fd.ctl.WriteString("close") 175 if err != nil { 176 return err 177 } 178 } 179 err := fd.ctl.Close() 180 if fd.data != nil { 181 if err1 := fd.data.Close(); err1 != nil && err == nil { 182 err = err1 183 } 184 } 185 if fd.listen != nil { 186 if err1 := fd.listen.Close(); err1 != nil && err == nil { 187 err = err1 188 } 189 } 190 fd.ctl = nil 191 fd.data = nil 192 fd.listen = nil 193 return err 194 } 195 196 // This method is only called via Conn. 197 func (fd *netFD) dup() (*os.File, error) { 198 if !fd.ok() || fd.data == nil { 199 return nil, syscall.EINVAL 200 } 201 return fd.file(fd.data, fd.dir+"/data") 202 } 203 204 func (l *TCPListener) dup() (*os.File, error) { 205 if !l.fd.ok() { 206 return nil, syscall.EINVAL 207 } 208 return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl") 209 } 210 211 func (fd *netFD) file(f *os.File, s string) (*os.File, error) { 212 dfd, err := syscall.Dup(int(f.Fd()), -1) 213 if err != nil { 214 return nil, os.NewSyscallError("dup", err) 215 } 216 return os.NewFile(uintptr(dfd), s), nil 217 } 218 219 func (fd *netFD) setDeadline(t time.Time) error { 220 return setDeadlineImpl(fd, t, 'r'+'w') 221 } 222 223 func (fd *netFD) setReadDeadline(t time.Time) error { 224 return setDeadlineImpl(fd, t, 'r') 225 } 226 227 func (fd *netFD) setWriteDeadline(t time.Time) error { 228 return setDeadlineImpl(fd, t, 'w') 229 } 230 231 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error { 232 d := t.Sub(time.Now()) 233 if mode == 'r' || mode == 'r'+'w' { 234 fd.rtimedout.setFalse() 235 } 236 if mode == 'w' || mode == 'r'+'w' { 237 fd.wtimedout.setFalse() 238 } 239 if t.IsZero() || d < 0 { 240 // Stop timer 241 if mode == 'r' || mode == 'r'+'w' { 242 if fd.rtimer != nil { 243 fd.rtimer.Stop() 244 } 245 fd.rtimer = nil 246 } 247 if mode == 'w' || mode == 'r'+'w' { 248 if fd.wtimer != nil { 249 fd.wtimer.Stop() 250 } 251 fd.wtimer = nil 252 } 253 } else { 254 // Interrupt I/O operation once timer has expired 255 if mode == 'r' || mode == 'r'+'w' { 256 fd.rtimer = time.AfterFunc(d, func() { 257 fd.rtimedout.setTrue() 258 if fd.raio != nil { 259 fd.raio.Cancel() 260 } 261 }) 262 } 263 if mode == 'w' || mode == 'r'+'w' { 264 fd.wtimer = time.AfterFunc(d, func() { 265 fd.wtimedout.setTrue() 266 if fd.waio != nil { 267 fd.waio.Cancel() 268 } 269 }) 270 } 271 } 272 if !t.IsZero() && d < 0 { 273 // Interrupt current I/O operation 274 if mode == 'r' || mode == 'r'+'w' { 275 fd.rtimedout.setTrue() 276 if fd.raio != nil { 277 fd.raio.Cancel() 278 } 279 } 280 if mode == 'w' || mode == 'r'+'w' { 281 fd.wtimedout.setTrue() 282 if fd.waio != nil { 283 fd.waio.Cancel() 284 } 285 } 286 } 287 return nil 288 } 289 290 func setReadBuffer(fd *netFD, bytes int) error { 291 return syscall.EPLAN9 292 } 293 294 func setWriteBuffer(fd *netFD, bytes int) error { 295 return syscall.EPLAN9 296 } 297 298 func isHangup(err error) bool { 299 return err != nil && stringsHasSuffix(err.Error(), "Hangup") 300 } 301 302 func isInterrupted(err error) bool { 303 return err != nil && stringsHasSuffix(err.Error(), "interrupted") 304 }