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  }