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  }