Source file src/internal/poll/fd_plan9.go

     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 poll
     6  
     7  import (
     8  	"errors"
     9  	"internal/stringslite"
    10  	"io"
    11  	"sync"
    12  	"syscall"
    13  	"time"
    14  )
    15  
    16  type FD struct {
    17  	// Lock sysfd and serialize access to Read and Write methods.
    18  	fdmu fdMutex
    19  
    20  	Destroy func()
    21  
    22  	// deadlines
    23  	rmu       sync.Mutex
    24  	wmu       sync.Mutex
    25  	raio      *asyncIO
    26  	waio      *asyncIO
    27  	rtimer    *time.Timer
    28  	wtimer    *time.Timer
    29  	rtimedout bool // set true when read deadline has been reached
    30  	wtimedout bool // set true when write deadline has been reached
    31  
    32  	// Whether this is a normal file.
    33  	// On Plan 9 we do not use this package for ordinary files,
    34  	// so this is always false, but the field is present because
    35  	// shared code in fd_mutex.go checks it.
    36  	isFile bool
    37  }
    38  
    39  // We need this to close out a file descriptor when it is unlocked,
    40  // but the real implementation has to live in the net package because
    41  // it uses os.File's.
    42  func (fd *FD) destroy() error {
    43  	if fd.Destroy != nil {
    44  		fd.Destroy()
    45  	}
    46  	return nil
    47  }
    48  
    49  // Close handles the locking for closing an FD. The real operation
    50  // is in the net package.
    51  func (fd *FD) Close() error {
    52  	if !fd.fdmu.increfAndClose() {
    53  		return errClosing(fd.isFile)
    54  	}
    55  	return nil
    56  }
    57  
    58  // Read implements io.Reader.
    59  func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
    60  	if err := fd.readLock(); err != nil {
    61  		return 0, err
    62  	}
    63  	defer fd.readUnlock()
    64  	if len(b) == 0 {
    65  		return 0, nil
    66  	}
    67  	fd.rmu.Lock()
    68  	if fd.rtimedout {
    69  		fd.rmu.Unlock()
    70  		return 0, ErrDeadlineExceeded
    71  	}
    72  	fd.raio = newAsyncIO(fn, b)
    73  	fd.rmu.Unlock()
    74  	n, err := fd.raio.Wait()
    75  	fd.raio = nil
    76  	if isHangup(err) {
    77  		err = io.EOF
    78  	}
    79  	if isInterrupted(err) {
    80  		err = ErrDeadlineExceeded
    81  	}
    82  	if fd.closing() {
    83  		err = errClosing(fd.isFile)
    84  	}
    85  	return n, err
    86  }
    87  
    88  // Write implements io.Writer.
    89  func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
    90  	if err := fd.writeLock(); err != nil {
    91  		return 0, err
    92  	}
    93  	defer fd.writeUnlock()
    94  	fd.wmu.Lock()
    95  	if fd.wtimedout {
    96  		fd.wmu.Unlock()
    97  		return 0, ErrDeadlineExceeded
    98  	}
    99  	fd.waio = newAsyncIO(fn, b)
   100  	fd.wmu.Unlock()
   101  	n, err := fd.waio.Wait()
   102  	fd.waio = nil
   103  	if isInterrupted(err) {
   104  		err = ErrDeadlineExceeded
   105  	}
   106  	return n, err
   107  }
   108  
   109  // SetDeadline sets the read and write deadlines associated with fd.
   110  func (fd *FD) SetDeadline(t time.Time) error {
   111  	return setDeadlineImpl(fd, t, 'r'+'w')
   112  }
   113  
   114  // SetReadDeadline sets the read deadline associated with fd.
   115  func (fd *FD) SetReadDeadline(t time.Time) error {
   116  	return setDeadlineImpl(fd, t, 'r')
   117  }
   118  
   119  // SetWriteDeadline sets the write deadline associated with fd.
   120  func (fd *FD) SetWriteDeadline(t time.Time) error {
   121  	return setDeadlineImpl(fd, t, 'w')
   122  }
   123  
   124  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   125  	d := t.Sub(time.Now())
   126  	if mode == 'r' || mode == 'r'+'w' {
   127  		fd.rmu.Lock()
   128  		defer fd.rmu.Unlock()
   129  		if fd.rtimer != nil {
   130  			fd.rtimer.Stop()
   131  			fd.rtimer = nil
   132  		}
   133  		fd.rtimedout = false
   134  	}
   135  	if mode == 'w' || mode == 'r'+'w' {
   136  		fd.wmu.Lock()
   137  		defer fd.wmu.Unlock()
   138  		if fd.wtimer != nil {
   139  			fd.wtimer.Stop()
   140  			fd.wtimer = nil
   141  		}
   142  		fd.wtimedout = false
   143  	}
   144  	if !t.IsZero() && d > 0 {
   145  		// Interrupt I/O operation once timer has expired
   146  		if mode == 'r' || mode == 'r'+'w' {
   147  			var timer *time.Timer
   148  			timer = time.AfterFunc(d, func() {
   149  				fd.rmu.Lock()
   150  				defer fd.rmu.Unlock()
   151  				if fd.rtimer != timer {
   152  					// deadline was changed
   153  					return
   154  				}
   155  				fd.rtimedout = true
   156  				if fd.raio != nil {
   157  					fd.raio.Cancel()
   158  				}
   159  			})
   160  			fd.rtimer = timer
   161  		}
   162  		if mode == 'w' || mode == 'r'+'w' {
   163  			var timer *time.Timer
   164  			timer = time.AfterFunc(d, func() {
   165  				fd.wmu.Lock()
   166  				defer fd.wmu.Unlock()
   167  				if fd.wtimer != timer {
   168  					// deadline was changed
   169  					return
   170  				}
   171  				fd.wtimedout = true
   172  				if fd.waio != nil {
   173  					fd.waio.Cancel()
   174  				}
   175  			})
   176  			fd.wtimer = timer
   177  		}
   178  	}
   179  	if !t.IsZero() && d <= 0 {
   180  		// Interrupt current I/O operation
   181  		if mode == 'r' || mode == 'r'+'w' {
   182  			fd.rtimedout = true
   183  			if fd.raio != nil {
   184  				fd.raio.Cancel()
   185  			}
   186  		}
   187  		if mode == 'w' || mode == 'r'+'w' {
   188  			fd.wtimedout = true
   189  			if fd.waio != nil {
   190  				fd.waio.Cancel()
   191  			}
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  // On Plan 9 only, expose the locking for the net code.
   198  
   199  // ReadLock wraps FD.readLock.
   200  func (fd *FD) ReadLock() error {
   201  	return fd.readLock()
   202  }
   203  
   204  // ReadUnlock wraps FD.readUnlock.
   205  func (fd *FD) ReadUnlock() {
   206  	fd.readUnlock()
   207  }
   208  
   209  func isHangup(err error) bool {
   210  	return err != nil && stringslite.HasSuffix(err.Error(), "Hangup")
   211  }
   212  
   213  func isInterrupted(err error) bool {
   214  	return err != nil && stringslite.HasSuffix(err.Error(), "interrupted")
   215  }
   216  
   217  // IsPollDescriptor reports whether fd is the descriptor being used by the poller.
   218  // This is only used for testing.
   219  func IsPollDescriptor(fd uintptr) bool {
   220  	return false
   221  }
   222  
   223  // RawControl invokes the user-defined function f for a non-IO
   224  // operation.
   225  func (fd *FD) RawControl(f func(uintptr)) error {
   226  	return errors.New("not implemented")
   227  }
   228  
   229  // RawRead invokes the user-defined function f for a read operation.
   230  func (fd *FD) RawRead(f func(uintptr) bool) error {
   231  	return errors.New("not implemented")
   232  }
   233  
   234  // RawWrite invokes the user-defined function f for a write operation.
   235  func (fd *FD) RawWrite(f func(uintptr) bool) error {
   236  	return errors.New("not implemented")
   237  }
   238  
   239  func DupCloseOnExec(fd int) (int, string, error) {
   240  	nfd, err := syscall.Dup(int(fd), -1)
   241  	if err != nil {
   242  		return 0, "dup", err
   243  	}
   244  	// Plan9 has no syscall.CloseOnExec but
   245  	// its forkAndExecInChild closes all fds
   246  	// not related to the fork+exec.
   247  	return nfd, "", nil
   248  }
   249  

View as plain text