github.com/cbeuw/gotfo@v0.0.0-20180331191851-f2b091af84de/fd_go110_unix.go (about) 1 // +build go1.10 2 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris 3 4 // https://github.com/golang/go/commit/382d4928b8a758a91f06de9e6cb10b92bb882eff 5 package gotfo 6 7 import "syscall" 8 import "net" 9 10 type pollFD struct { 11 // Lock sysfd and serialize access to Read and Write methods. 12 fdmu fdMutex 13 14 // System file descriptor. Immutable until Close. 15 sysfd int 16 17 // I/O poller. 18 pd pollDesc 19 20 // Writev cache. 21 iovecs *[]syscall.Iovec 22 23 // Semaphore signaled when file is closed. 24 csema uint32 25 26 // Whether this is a streaming descriptor, as opposed to a 27 // packet-based descriptor like a UDP socket. Immutable. 28 IsStream bool 29 30 // Whether a zero byte read indicates EOF. This is false for a 31 // message based socket connection. 32 ZeroReadIsEOF bool 33 34 // Whether this is a file rather than a network socket. 35 isFile bool 36 37 // Whether this file has been set to blocking mode. 38 isBlocking bool 39 } 40 41 // Network file descriptor. 42 type netFD struct { 43 pollFD 44 45 // immutable until Close 46 family int 47 sotype int 48 isConnected bool 49 net string 50 laddr net.Addr 51 raddr net.Addr 52 } 53 54 func newFD(fd int) *netFD { 55 nfd := &netFD{ 56 pollFD: pollFD{ 57 sysfd: fd, 58 IsStream: true, 59 ZeroReadIsEOF: true, 60 }, 61 family: syscall.AF_INET, 62 sotype: syscall.SOCK_STREAM, 63 net: "tcp", 64 } 65 66 return nfd 67 } 68 69 func (fd *netFD) init() error { 70 return fd.pd.init(fd) 71 } 72 73 func (fd *pollFD) incref() error { 74 if !fd.fdmu.incref() { 75 return errClosing 76 } 77 return nil 78 } 79 80 // decref removes a reference from fd. 81 // It also closes fd when the state of fd is set to closed and there 82 // is no remaining reference. 83 func (fd *pollFD) decref() error { 84 if fd.fdmu.decref() { 85 return fd.destroy() 86 } 87 return nil 88 } 89 90 // Destroy closes the file descriptor. This is called when there are 91 // no remaining references. 92 func (fd *pollFD) destroy() error { 93 // Poller may want to unregister fd in readiness notification mechanism, 94 // so this must be executed before CloseFunc. 95 fd.pd.close() 96 err := syscall.Close(fd.sysfd) 97 fd.sysfd = -1 98 runtime_Semrelease(&fd.csema) 99 return err 100 } 101 102 // Close closes the FD. The underlying file descriptor is closed by the 103 // destroy method when there are no remaining references. 104 func (fd *pollFD) Close() error { 105 if !fd.fdmu.increfAndClose() { 106 return errClosing 107 } 108 109 // Unblock any I/O. Once it all unblocks and returns, 110 // so that it cannot be referring to fd.sysfd anymore, 111 // the final decref will close fd.sysfd. This should happen 112 // fairly quickly, since all the I/O is non-blocking, and any 113 // attempts to block in the pollDesc will return errClosing(fd.isFile). 114 fd.pd.evict() 115 116 // The call to decref will call destroy if there are no other 117 // references. 118 err := fd.decref() 119 120 // Wait until the descriptor is closed. If this was the only 121 // reference, it is already closed. Only wait if the file has 122 // not been set to blocking mode, as otherwise any current I/O 123 // may be blocking, and that would block the Close. 124 if !fd.isBlocking { 125 runtime_Semacquire(&fd.csema) 126 } 127 128 return err 129 } 130 131 // Shutdown wraps the shutdown network call. 132 func (fd *pollFD) Shutdown(how int) error { 133 if err := fd.incref(); err != nil { 134 return err 135 } 136 defer fd.decref() 137 return syscall.Shutdown(fd.sysfd, how) 138 }