github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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  }