github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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  func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
    54  	if fd.rtimedout.isSet() {
    55  		return 0, ErrTimeout
    56  	}
    57  	if err := fd.readLock(); err != nil {
    58  		return 0, err
    59  	}
    60  	defer fd.readUnlock()
    61  	if len(b) == 0 {
    62  		return 0, nil
    63  	}
    64  	fd.raio = newAsyncIO(fn, b)
    65  	n, err := fd.raio.Wait()
    66  	fd.raio = nil
    67  	if isHangup(err) {
    68  		err = io.EOF
    69  	}
    70  	if isInterrupted(err) {
    71  		err = ErrTimeout
    72  	}
    73  	return n, err
    74  }
    75  
    76  func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
    77  	if fd.wtimedout.isSet() {
    78  		return 0, ErrTimeout
    79  	}
    80  	if err := fd.writeLock(); err != nil {
    81  		return 0, err
    82  	}
    83  	defer fd.writeUnlock()
    84  	fd.waio = newAsyncIO(fn, b)
    85  	n, err := fd.waio.Wait()
    86  	fd.waio = nil
    87  	if isInterrupted(err) {
    88  		err = ErrTimeout
    89  	}
    90  	return n, err
    91  }
    92  
    93  func (fd *FD) SetDeadline(t time.Time) error {
    94  	return setDeadlineImpl(fd, t, 'r'+'w')
    95  }
    96  
    97  func (fd *FD) SetReadDeadline(t time.Time) error {
    98  	return setDeadlineImpl(fd, t, 'r')
    99  }
   100  
   101  func (fd *FD) SetWriteDeadline(t time.Time) error {
   102  	return setDeadlineImpl(fd, t, 'w')
   103  }
   104  
   105  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   106  	d := t.Sub(time.Now())
   107  	if mode == 'r' || mode == 'r'+'w' {
   108  		fd.rtimedout.setFalse()
   109  	}
   110  	if mode == 'w' || mode == 'r'+'w' {
   111  		fd.wtimedout.setFalse()
   112  	}
   113  	if t.IsZero() || d < 0 {
   114  		// Stop timer
   115  		if mode == 'r' || mode == 'r'+'w' {
   116  			if fd.rtimer != nil {
   117  				fd.rtimer.Stop()
   118  			}
   119  			fd.rtimer = nil
   120  		}
   121  		if mode == 'w' || mode == 'r'+'w' {
   122  			if fd.wtimer != nil {
   123  				fd.wtimer.Stop()
   124  			}
   125  			fd.wtimer = nil
   126  		}
   127  	} else {
   128  		// Interrupt I/O operation once timer has expired
   129  		if mode == 'r' || mode == 'r'+'w' {
   130  			fd.rtimer = time.AfterFunc(d, func() {
   131  				fd.rtimedout.setTrue()
   132  				if fd.raio != nil {
   133  					fd.raio.Cancel()
   134  				}
   135  			})
   136  		}
   137  		if mode == 'w' || mode == 'r'+'w' {
   138  			fd.wtimer = time.AfterFunc(d, func() {
   139  				fd.wtimedout.setTrue()
   140  				if fd.waio != nil {
   141  					fd.waio.Cancel()
   142  				}
   143  			})
   144  		}
   145  	}
   146  	if !t.IsZero() && d < 0 {
   147  		// Interrupt current I/O operation
   148  		if mode == 'r' || mode == 'r'+'w' {
   149  			fd.rtimedout.setTrue()
   150  			if fd.raio != nil {
   151  				fd.raio.Cancel()
   152  			}
   153  		}
   154  		if mode == 'w' || mode == 'r'+'w' {
   155  			fd.wtimedout.setTrue()
   156  			if fd.waio != nil {
   157  				fd.waio.Cancel()
   158  			}
   159  		}
   160  	}
   161  	return nil
   162  }
   163  
   164  // On Plan 9 only, expose the locking for the net code.
   165  
   166  func (fd *FD) ReadLock() error {
   167  	return fd.readLock()
   168  }
   169  
   170  func (fd *FD) ReadUnlock() {
   171  	fd.readUnlock()
   172  }
   173  
   174  func isHangup(err error) bool {
   175  	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
   176  }
   177  
   178  func isInterrupted(err error) bool {
   179  	return err != nil && stringsHasSuffix(err.Error(), "interrupted")
   180  }
   181  
   182  func PollDescriptor() uintptr {
   183  	return ^uintptr(0)
   184  }