fd_plan9.mx raw

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