github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 "syscall" 11 "time" 12 ) 13 14 // Network file descriptor. 15 type netFD struct { 16 // locking/lifetime of sysfd + serialize access to Read and Write methods 17 fdmu fdMutex 18 19 // immutable until Close 20 net string 21 n string 22 dir string 23 ctl, data *os.File 24 laddr, raddr Addr 25 } 26 27 var ( 28 netdir string // default network 29 ) 30 31 func sysInit() { 32 netdir = "/net" 33 } 34 35 func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { 36 // On plan9, use the relatively inefficient 37 // goroutine-racing implementation. 38 return dialChannel(net, ra, dialer, deadline) 39 } 40 41 func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { 42 return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil 43 } 44 45 func (fd *netFD) init() error { 46 // stub for future fd.pd.Init(fd) 47 return nil 48 } 49 50 func (fd *netFD) name() string { 51 var ls, rs string 52 if fd.laddr != nil { 53 ls = fd.laddr.String() 54 } 55 if fd.raddr != nil { 56 rs = fd.raddr.String() 57 } 58 return fd.net + ":" + ls + "->" + rs 59 } 60 61 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } 62 63 func (fd *netFD) destroy() { 64 if !fd.ok() { 65 return 66 } 67 err := fd.ctl.Close() 68 if fd.data != nil { 69 if err1 := fd.data.Close(); err1 != nil && err == nil { 70 err = err1 71 } 72 } 73 fd.ctl = nil 74 fd.data = nil 75 } 76 77 // Add a reference to this fd. 78 // Returns an error if the fd cannot be used. 79 func (fd *netFD) incref() error { 80 if !fd.fdmu.Incref() { 81 return errClosing 82 } 83 return nil 84 } 85 86 // Remove a reference to this FD and close if we've been asked to do so 87 // (and there are no references left). 88 func (fd *netFD) decref() { 89 if fd.fdmu.Decref() { 90 fd.destroy() 91 } 92 } 93 94 // Add a reference to this fd and lock for reading. 95 // Returns an error if the fd cannot be used. 96 func (fd *netFD) readLock() error { 97 if !fd.fdmu.RWLock(true) { 98 return errClosing 99 } 100 return nil 101 } 102 103 // Unlock for reading and remove a reference to this FD. 104 func (fd *netFD) readUnlock() { 105 if fd.fdmu.RWUnlock(true) { 106 fd.destroy() 107 } 108 } 109 110 // Add a reference to this fd and lock for writing. 111 // Returns an error if the fd cannot be used. 112 func (fd *netFD) writeLock() error { 113 if !fd.fdmu.RWLock(false) { 114 return errClosing 115 } 116 return nil 117 } 118 119 // Unlock for writing and remove a reference to this FD. 120 func (fd *netFD) writeUnlock() { 121 if fd.fdmu.RWUnlock(false) { 122 fd.destroy() 123 } 124 } 125 126 func (fd *netFD) Read(b []byte) (n int, err error) { 127 if !fd.ok() || fd.data == nil { 128 return 0, syscall.EINVAL 129 } 130 if err := fd.readLock(); err != nil { 131 return 0, err 132 } 133 defer fd.readUnlock() 134 n, err = fd.data.Read(b) 135 if fd.net == "udp" && err == io.EOF { 136 n = 0 137 err = nil 138 } 139 return 140 } 141 142 func (fd *netFD) Write(b []byte) (n int, err error) { 143 if !fd.ok() || fd.data == nil { 144 return 0, syscall.EINVAL 145 } 146 if err := fd.writeLock(); err != nil { 147 return 0, err 148 } 149 defer fd.writeUnlock() 150 return fd.data.Write(b) 151 } 152 153 func (fd *netFD) closeRead() error { 154 if !fd.ok() { 155 return syscall.EINVAL 156 } 157 return syscall.EPLAN9 158 } 159 160 func (fd *netFD) closeWrite() error { 161 if !fd.ok() { 162 return syscall.EINVAL 163 } 164 return syscall.EPLAN9 165 } 166 167 func (fd *netFD) Close() error { 168 if !fd.fdmu.IncrefAndClose() { 169 return errClosing 170 } 171 if !fd.ok() { 172 return syscall.EINVAL 173 } 174 if fd.net == "tcp" { 175 // The following line is required to unblock Reads. 176 // For some reason, WriteString returns an error: 177 // "write /net/tcp/39/listen: inappropriate use of fd" 178 // But without it, Reads on dead conns hang forever. 179 // See Issue 9554. 180 fd.ctl.WriteString("hangup") 181 } 182 err := fd.ctl.Close() 183 if fd.data != nil { 184 if err1 := fd.data.Close(); err1 != nil && err == nil { 185 err = err1 186 } 187 } 188 fd.ctl = nil 189 fd.data = nil 190 return err 191 } 192 193 // This method is only called via Conn. 194 func (fd *netFD) dup() (*os.File, error) { 195 if !fd.ok() || fd.data == nil { 196 return nil, syscall.EINVAL 197 } 198 return fd.file(fd.data, fd.dir+"/data") 199 } 200 201 func (l *TCPListener) dup() (*os.File, error) { 202 if !l.fd.ok() { 203 return nil, syscall.EINVAL 204 } 205 return l.fd.file(l.fd.ctl, l.fd.dir+"/ctl") 206 } 207 208 func (fd *netFD) file(f *os.File, s string) (*os.File, error) { 209 syscall.ForkLock.RLock() 210 dfd, err := syscall.Dup(int(f.Fd()), -1) 211 syscall.ForkLock.RUnlock() 212 if err != nil { 213 return nil, os.NewSyscallError("dup", err) 214 } 215 return os.NewFile(uintptr(dfd), s), nil 216 } 217 218 func (fd *netFD) setDeadline(t time.Time) error { 219 return syscall.EPLAN9 220 } 221 222 func (fd *netFD) setReadDeadline(t time.Time) error { 223 return syscall.EPLAN9 224 } 225 226 func (fd *netFD) setWriteDeadline(t time.Time) error { 227 return syscall.EPLAN9 228 } 229 230 func setReadBuffer(fd *netFD, bytes int) error { 231 return syscall.EPLAN9 232 } 233 234 func setWriteBuffer(fd *netFD, bytes int) error { 235 return syscall.EPLAN9 236 }