github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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  
    34  // We need this to close out a file descriptor when it is unlocked,
    35  // but the real implementation has to live in the net package because
    36  // it uses os.File's.
    37  func (fd *FD) destroy() error {
    38  	if fd.Destroy != nil {
    39  		fd.Destroy()
    40  	}
    41  	return nil
    42  }
    43  
    44  // Close handles the locking for closing an FD. The real operation
    45  // is in the net package.
    46  func (fd *FD) Close() error {
    47  	if !fd.fdmu.increfAndClose() {
    48  		return ErrClosing
    49  	}
    50  	return nil
    51  }
    52  
    53  // Read implements io.Reader.
    54  func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
    55  	if fd.rtimedout.isSet() {
    56  		return 0, ErrTimeout
    57  	}
    58  	if err := fd.readLock(); err != nil {
    59  		return 0, err
    60  	}
    61  	defer fd.readUnlock()
    62  	if len(b) == 0 {
    63  		return 0, nil
    64  	}
    65  	fd.raio = newAsyncIO(fn, b)
    66  	n, err := fd.raio.Wait()
    67  	fd.raio = nil
    68  	if isHangup(err) {
    69  		err = io.EOF
    70  	}
    71  	if isInterrupted(err) {
    72  		err = ErrTimeout
    73  	}
    74  	return n, err
    75  }
    76  
    77  // Write implements io.Writer.
    78  func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
    79  	if fd.wtimedout.isSet() {
    80  		return 0, ErrTimeout
    81  	}
    82  	if err := fd.writeLock(); err != nil {
    83  		return 0, err
    84  	}
    85  	defer fd.writeUnlock()
    86  	fd.waio = newAsyncIO(fn, b)
    87  	n, err := fd.waio.Wait()
    88  	fd.waio = nil
    89  	if isInterrupted(err) {
    90  		err = ErrTimeout
    91  	}
    92  	return n, err
    93  }
    94  
    95  // SetDeadline sets the read and write deadlines associated with fd.
    96  func (fd *FD) SetDeadline(t time.Time) error {
    97  	return setDeadlineImpl(fd, t, 'r'+'w')
    98  }
    99  
   100  // SetReadDeadline sets the read deadline associated with fd.
   101  func (fd *FD) SetReadDeadline(t time.Time) error {
   102  	return setDeadlineImpl(fd, t, 'r')
   103  }
   104  
   105  // SetWriteDeadline sets the write deadline associated with fd.
   106  func (fd *FD) SetWriteDeadline(t time.Time) error {
   107  	return setDeadlineImpl(fd, t, 'w')
   108  }
   109  
   110  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   111  	d := t.Sub(time.Now())
   112  	if mode == 'r' || mode == 'r'+'w' {
   113  		fd.rtimedout.setFalse()
   114  	}
   115  	if mode == 'w' || mode == 'r'+'w' {
   116  		fd.wtimedout.setFalse()
   117  	}
   118  	if t.IsZero() || d < 0 {
   119  		// Stop timer
   120  		if mode == 'r' || mode == 'r'+'w' {
   121  			if fd.rtimer != nil {
   122  				fd.rtimer.Stop()
   123  			}
   124  			fd.rtimer = nil
   125  		}
   126  		if mode == 'w' || mode == 'r'+'w' {
   127  			if fd.wtimer != nil {
   128  				fd.wtimer.Stop()
   129  			}
   130  			fd.wtimer = nil
   131  		}
   132  	} else {
   133  		// Interrupt I/O operation once timer has expired
   134  		if mode == 'r' || mode == 'r'+'w' {
   135  			fd.rtimer = time.AfterFunc(d, func() {
   136  				fd.rtimedout.setTrue()
   137  				if fd.raio != nil {
   138  					fd.raio.Cancel()
   139  				}
   140  			})
   141  		}
   142  		if mode == 'w' || mode == 'r'+'w' {
   143  			fd.wtimer = time.AfterFunc(d, func() {
   144  				fd.wtimedout.setTrue()
   145  				if fd.waio != nil {
   146  					fd.waio.Cancel()
   147  				}
   148  			})
   149  		}
   150  	}
   151  	if !t.IsZero() && d < 0 {
   152  		// Interrupt current I/O operation
   153  		if mode == 'r' || mode == 'r'+'w' {
   154  			fd.rtimedout.setTrue()
   155  			if fd.raio != nil {
   156  				fd.raio.Cancel()
   157  			}
   158  		}
   159  		if mode == 'w' || mode == 'r'+'w' {
   160  			fd.wtimedout.setTrue()
   161  			if fd.waio != nil {
   162  				fd.waio.Cancel()
   163  			}
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  // On Plan 9 only, expose the locking for the net code.
   170  
   171  // ReadLock wraps FD.readLock.
   172  func (fd *FD) ReadLock() error {
   173  	return fd.readLock()
   174  }
   175  
   176  // ReadUnlock wraps FD.readUnlock.
   177  func (fd *FD) ReadUnlock() {
   178  	fd.readUnlock()
   179  }
   180  
   181  func isHangup(err error) bool {
   182  	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
   183  }
   184  
   185  func isInterrupted(err error) bool {
   186  	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
   187  }
   188  
   189  // PollDescriptor returns the descriptor being used by the poller,
   190  // or ^uintptr(0) if there isn't one. This is only used for testing.
   191  func PollDescriptor() uintptr {
   192  	return ^uintptr(0)
   193  }