github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/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  	"io"
     9  	"sync/atomic"
    10  	"time"
    11  )
    12  
    13  type atomicBool int32
    14  
    15  func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
    16  func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
    17  func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
    18  
    19  type FD struct {
    20  	// Lock sysfd and serialize access to Read and Write methods.
    21  	fdmu fdMutex
    22  
    23  	Destroy func()
    24  
    25  	// deadlines
    26  	raio      *asyncIO
    27  	waio      *asyncIO
    28  	rtimer    *time.Timer
    29  	wtimer    *time.Timer
    30  	rtimedout atomicBool // set true when read deadline has been reached
    31  	wtimedout atomicBool // set true when write deadline has been reached
    32  
    33  	// Whether this is a normal file.
    34  	// On Plan 9 we do not use this package for ordinary files,
    35  	// so this is always false, but the field is present because
    36  	// shared code in fd_mutex.go checks it.
    37  	isFile bool
    38  }
    39  
    40  // We need this to close out a file descriptor when it is unlocked,
    41  // but the real implementation has to live in the net package because
    42  // it uses os.File's.
    43  func (fd *FD) destroy() error {
    44  	if fd.Destroy != nil {
    45  		fd.Destroy()
    46  	}
    47  	return nil
    48  }
    49  
    50  // Close handles the locking for closing an FD. The real operation
    51  // is in the net package.
    52  func (fd *FD) Close() error {
    53  	if !fd.fdmu.increfAndClose() {
    54  		return errClosing(fd.isFile)
    55  	}
    56  	return nil
    57  }
    58  
    59  // Read implements io.Reader.
    60  func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
    61  	if fd.rtimedout.isSet() {
    62  		return 0, ErrTimeout
    63  	}
    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.raio = newAsyncIO(fn, b)
    72  	n, err := fd.raio.Wait()
    73  	fd.raio = nil
    74  	if isHangup(err) {
    75  		err = io.EOF
    76  	}
    77  	if isInterrupted(err) {
    78  		err = ErrTimeout
    79  	}
    80  	return n, err
    81  }
    82  
    83  // Write implements io.Writer.
    84  func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
    85  	if fd.wtimedout.isSet() {
    86  		return 0, ErrTimeout
    87  	}
    88  	if err := fd.writeLock(); err != nil {
    89  		return 0, err
    90  	}
    91  	defer fd.writeUnlock()
    92  	fd.waio = newAsyncIO(fn, b)
    93  	n, err := fd.waio.Wait()
    94  	fd.waio = nil
    95  	if isInterrupted(err) {
    96  		err = ErrTimeout
    97  	}
    98  	return n, err
    99  }
   100  
   101  // SetDeadline sets the read and write deadlines associated with fd.
   102  func (fd *FD) SetDeadline(t time.Time) error {
   103  	return setDeadlineImpl(fd, t, 'r'+'w')
   104  }
   105  
   106  // SetReadDeadline sets the read deadline associated with fd.
   107  func (fd *FD) SetReadDeadline(t time.Time) error {
   108  	return setDeadlineImpl(fd, t, 'r')
   109  }
   110  
   111  // SetWriteDeadline sets the write deadline associated with fd.
   112  func (fd *FD) SetWriteDeadline(t time.Time) error {
   113  	return setDeadlineImpl(fd, t, 'w')
   114  }
   115  
   116  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   117  	d := t.Sub(time.Now())
   118  	if mode == 'r' || mode == 'r'+'w' {
   119  		fd.rtimedout.setFalse()
   120  	}
   121  	if mode == 'w' || mode == 'r'+'w' {
   122  		fd.wtimedout.setFalse()
   123  	}
   124  	if t.IsZero() || d < 0 {
   125  		// Stop timer
   126  		if mode == 'r' || mode == 'r'+'w' {
   127  			if fd.rtimer != nil {
   128  				fd.rtimer.Stop()
   129  			}
   130  			fd.rtimer = nil
   131  		}
   132  		if mode == 'w' || mode == 'r'+'w' {
   133  			if fd.wtimer != nil {
   134  				fd.wtimer.Stop()
   135  			}
   136  			fd.wtimer = nil
   137  		}
   138  	} else {
   139  		// Interrupt I/O operation once timer has expired
   140  		if mode == 'r' || mode == 'r'+'w' {
   141  			fd.rtimer = time.AfterFunc(d, func() {
   142  				fd.rtimedout.setTrue()
   143  				if fd.raio != nil {
   144  					fd.raio.Cancel()
   145  				}
   146  			})
   147  		}
   148  		if mode == 'w' || mode == 'r'+'w' {
   149  			fd.wtimer = time.AfterFunc(d, func() {
   150  				fd.wtimedout.setTrue()
   151  				if fd.waio != nil {
   152  					fd.waio.Cancel()
   153  				}
   154  			})
   155  		}
   156  	}
   157  	if !t.IsZero() && d < 0 {
   158  		// Interrupt current I/O operation
   159  		if mode == 'r' || mode == 'r'+'w' {
   160  			fd.rtimedout.setTrue()
   161  			if fd.raio != nil {
   162  				fd.raio.Cancel()
   163  			}
   164  		}
   165  		if mode == 'w' || mode == 'r'+'w' {
   166  			fd.wtimedout.setTrue()
   167  			if fd.waio != nil {
   168  				fd.waio.Cancel()
   169  			}
   170  		}
   171  	}
   172  	return nil
   173  }
   174  
   175  // On Plan 9 only, expose the locking for the net code.
   176  
   177  // ReadLock wraps FD.readLock.
   178  func (fd *FD) ReadLock() error {
   179  	return fd.readLock()
   180  }
   181  
   182  // ReadUnlock wraps FD.readUnlock.
   183  func (fd *FD) ReadUnlock() {
   184  	fd.readUnlock()
   185  }
   186  
   187  func isHangup(err error) bool {
   188  	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
   189  }
   190  
   191  func isInterrupted(err error) bool {
   192  	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
   193  }
   194  
   195  // PollDescriptor returns the descriptor being used by the poller,
   196  // or ^uintptr(0) if there isn't one. This is only used for testing.
   197  func PollDescriptor() uintptr {
   198  	return ^uintptr(0)
   199  }