github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/internal/poll/fd_poll_runtime.go (about)

     1  // Copyright 2013 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  // +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
     6  
     7  package poll
     8  
     9  import (
    10  	"errors"
    11  	"sync"
    12  	"syscall"
    13  	"time"
    14  )
    15  
    16  // runtimeNano returns the current value of the runtime clock in nanoseconds.
    17  func runtimeNano() int64
    18  
    19  func runtime_pollServerInit()
    20  func runtime_pollServerDescriptor() uintptr
    21  func runtime_pollOpen(fd uintptr) (uintptr, int)
    22  func runtime_pollClose(ctx uintptr)
    23  func runtime_pollWait(ctx uintptr, mode int) int
    24  func runtime_pollWaitCanceled(ctx uintptr, mode int) int
    25  func runtime_pollReset(ctx uintptr, mode int) int
    26  func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
    27  func runtime_pollUnblock(ctx uintptr)
    28  
    29  type pollDesc struct {
    30  	runtimeCtx uintptr
    31  }
    32  
    33  var serverInit sync.Once
    34  
    35  func (pd *pollDesc) init(fd *FD) error {
    36  	serverInit.Do(runtime_pollServerInit)
    37  	ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
    38  	if errno != 0 {
    39  		if ctx != 0 {
    40  			runtime_pollUnblock(ctx)
    41  			runtime_pollClose(ctx)
    42  		}
    43  		return syscall.Errno(errno)
    44  	}
    45  	pd.runtimeCtx = ctx
    46  	return nil
    47  }
    48  
    49  func (pd *pollDesc) close() {
    50  	if pd.runtimeCtx == 0 {
    51  		return
    52  	}
    53  	runtime_pollClose(pd.runtimeCtx)
    54  	pd.runtimeCtx = 0
    55  }
    56  
    57  // Evict evicts fd from the pending list, unblocking any I/O running on fd.
    58  func (pd *pollDesc) evict() {
    59  	if pd.runtimeCtx == 0 {
    60  		return
    61  	}
    62  	runtime_pollUnblock(pd.runtimeCtx)
    63  }
    64  
    65  func (pd *pollDesc) prepare(mode int) error {
    66  	if pd.runtimeCtx == 0 {
    67  		return nil
    68  	}
    69  	res := runtime_pollReset(pd.runtimeCtx, mode)
    70  	return convertErr(res)
    71  }
    72  
    73  func (pd *pollDesc) prepareRead() error {
    74  	return pd.prepare('r')
    75  }
    76  
    77  func (pd *pollDesc) prepareWrite() error {
    78  	return pd.prepare('w')
    79  }
    80  
    81  func (pd *pollDesc) wait(mode int) error {
    82  	if pd.runtimeCtx == 0 {
    83  		return errors.New("waiting for unsupported file type")
    84  	}
    85  	res := runtime_pollWait(pd.runtimeCtx, mode)
    86  	return convertErr(res)
    87  }
    88  
    89  func (pd *pollDesc) waitRead() error {
    90  	return pd.wait('r')
    91  }
    92  
    93  func (pd *pollDesc) waitWrite() error {
    94  	return pd.wait('w')
    95  }
    96  
    97  func (pd *pollDesc) waitCanceled(mode int) {
    98  	if pd.runtimeCtx == 0 {
    99  		return
   100  	}
   101  	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
   102  }
   103  
   104  func convertErr(res int) error {
   105  	switch res {
   106  	case 0:
   107  		return nil
   108  	case 1:
   109  		return ErrClosing
   110  	case 2:
   111  		return ErrTimeout
   112  	}
   113  	println("unreachable: ", res)
   114  	panic("unreachable")
   115  }
   116  
   117  // SetDeadline sets the read and write deadlines associated with fd.
   118  func (fd *FD) SetDeadline(t time.Time) error {
   119  	return setDeadlineImpl(fd, t, 'r'+'w')
   120  }
   121  
   122  // SetReadDeadline sets the read deadline associated with fd.
   123  func (fd *FD) SetReadDeadline(t time.Time) error {
   124  	return setDeadlineImpl(fd, t, 'r')
   125  }
   126  
   127  // SetWriteDeadline sets the write deadline associated with fd.
   128  func (fd *FD) SetWriteDeadline(t time.Time) error {
   129  	return setDeadlineImpl(fd, t, 'w')
   130  }
   131  
   132  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   133  	diff := int64(time.Until(t))
   134  	d := runtimeNano() + diff
   135  	if d <= 0 && diff > 0 {
   136  		// If the user has a deadline in the future, but the delay calculation
   137  		// overflows, then set the deadline to the maximum possible value.
   138  		d = 1<<63 - 1
   139  	}
   140  	if t.IsZero() {
   141  		d = 0
   142  	}
   143  	if err := fd.incref(); err != nil {
   144  		return err
   145  	}
   146  	if fd.pd.runtimeCtx == 0 {
   147  		return errors.New("file type does not support deadlines")
   148  	}
   149  	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
   150  	fd.decref()
   151  	return nil
   152  }
   153  
   154  // PollDescriptor returns the descriptor being used by the poller,
   155  // or ^uintptr(0) if there isn't one. This is only used for testing.
   156  func PollDescriptor() uintptr {
   157  	return runtime_pollServerDescriptor()
   158  }