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