github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/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  	"sync/atomic"
    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 atomic.Bool // set true when read deadline has been reached
    29  	wtimedout atomic.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.Load() {
    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.Load() {
    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  		fd.rtimedout.Store(false)
   126  	}
   127  	if mode == 'w' || mode == 'r'+'w' {
   128  		fd.wmu.Lock()
   129  		defer fd.wmu.Unlock()
   130  		fd.wtimedout.Store(false)
   131  	}
   132  	if t.IsZero() || d < 0 {
   133  		// Stop timer
   134  		if mode == 'r' || mode == 'r'+'w' {
   135  			if fd.rtimer != nil {
   136  				fd.rtimer.Stop()
   137  			}
   138  			fd.rtimer = nil
   139  		}
   140  		if mode == 'w' || mode == 'r'+'w' {
   141  			if fd.wtimer != nil {
   142  				fd.wtimer.Stop()
   143  			}
   144  			fd.wtimer = nil
   145  		}
   146  	} else {
   147  		// Interrupt I/O operation once timer has expired
   148  		if mode == 'r' || mode == 'r'+'w' {
   149  			fd.rtimer = time.AfterFunc(d, func() {
   150  				fd.rmu.Lock()
   151  				fd.rtimedout.Store(true)
   152  				if fd.raio != nil {
   153  					fd.raio.Cancel()
   154  				}
   155  				fd.rmu.Unlock()
   156  			})
   157  		}
   158  		if mode == 'w' || mode == 'r'+'w' {
   159  			fd.wtimer = time.AfterFunc(d, func() {
   160  				fd.wmu.Lock()
   161  				fd.wtimedout.Store(true)
   162  				if fd.waio != nil {
   163  					fd.waio.Cancel()
   164  				}
   165  				fd.wmu.Unlock()
   166  			})
   167  		}
   168  	}
   169  	if !t.IsZero() && d < 0 {
   170  		// Interrupt current I/O operation
   171  		if mode == 'r' || mode == 'r'+'w' {
   172  			fd.rtimedout.Store(true)
   173  			if fd.raio != nil {
   174  				fd.raio.Cancel()
   175  			}
   176  		}
   177  		if mode == 'w' || mode == 'r'+'w' {
   178  			fd.wtimedout.Store(true)
   179  			if fd.waio != nil {
   180  				fd.waio.Cancel()
   181  			}
   182  		}
   183  	}
   184  	return nil
   185  }
   186  
   187  // On Plan 9 only, expose the locking for the net code.
   188  
   189  // ReadLock wraps FD.readLock.
   190  func (fd *FD) ReadLock() error {
   191  	return fd.readLock()
   192  }
   193  
   194  // ReadUnlock wraps FD.readUnlock.
   195  func (fd *FD) ReadUnlock() {
   196  	fd.readUnlock()
   197  }
   198  
   199  func isHangup(err error) bool {
   200  	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
   201  }
   202  
   203  func isInterrupted(err error) bool {
   204  	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
   205  }
   206  
   207  // IsPollDescriptor reports whether fd is the descriptor being used by the poller.
   208  // This is only used for testing.
   209  func IsPollDescriptor(fd uintptr) bool {
   210  	return false
   211  }
   212  
   213  // RawControl invokes the user-defined function f for a non-IO
   214  // operation.
   215  func (fd *FD) RawControl(f func(uintptr)) error {
   216  	return errors.New("not implemented")
   217  }
   218  
   219  // RawRead invokes the user-defined function f for a read operation.
   220  func (fd *FD) RawRead(f func(uintptr) bool) error {
   221  	return errors.New("not implemented")
   222  }
   223  
   224  // RawWrite invokes the user-defined function f for a write operation.
   225  func (fd *FD) RawWrite(f func(uintptr) bool) error {
   226  	return errors.New("not implemented")
   227  }