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

View as plain text