github.com/sandwichdev/go-internals@v0.0.0-20210605002614-12311ac6b2c5/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 aix darwin dragonfly freebsd linux netbsd openbsd windows solaris
     6  
     7  package poll
     8  
     9  import (
    10  	"errors"
    11  	"sync"
    12  	"syscall"
    13  	"time"
    14  	_ "unsafe" // for go:linkname
    15  )
    16  
    17  // runtimeNano returns the current value of the runtime clock in nanoseconds.
    18  //go:linkname runtimeNano runtime.nanotime
    19  func runtimeNano() int64
    20  
    21  func runtime_pollServerInit()
    22  func runtime_pollOpen(fd uintptr) (uintptr, int)
    23  func runtime_pollClose(ctx uintptr)
    24  func runtime_pollWait(ctx uintptr, mode int) int
    25  func runtime_pollWaitCanceled(ctx uintptr, mode int) int
    26  func runtime_pollReset(ctx uintptr, mode int) int
    27  func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
    28  func runtime_pollUnblock(ctx uintptr)
    29  func runtime_isPollServerDescriptor(fd uintptr) bool
    30  
    31  type pollDesc struct {
    32  	runtimeCtx uintptr
    33  }
    34  
    35  var serverInit sync.Once
    36  
    37  func (pd *pollDesc) init(fd *FD) error {
    38  	serverInit.Do(runtime_pollServerInit)
    39  	ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
    40  	if errno != 0 {
    41  		if ctx != 0 {
    42  			runtime_pollUnblock(ctx)
    43  			runtime_pollClose(ctx)
    44  		}
    45  		return errnoErr(syscall.Errno(errno))
    46  	}
    47  	pd.runtimeCtx = ctx
    48  	return nil
    49  }
    50  
    51  func (pd *pollDesc) close() {
    52  	if pd.runtimeCtx == 0 {
    53  		return
    54  	}
    55  	runtime_pollClose(pd.runtimeCtx)
    56  	pd.runtimeCtx = 0
    57  }
    58  
    59  // Evict evicts fd from the pending list, unblocking any I/O running on fd.
    60  func (pd *pollDesc) evict() {
    61  	if pd.runtimeCtx == 0 {
    62  		return
    63  	}
    64  	runtime_pollUnblock(pd.runtimeCtx)
    65  }
    66  
    67  func (pd *pollDesc) prepare(mode int, isFile bool) error {
    68  	if pd.runtimeCtx == 0 {
    69  		return nil
    70  	}
    71  	res := runtime_pollReset(pd.runtimeCtx, mode)
    72  	return convertErr(res, isFile)
    73  }
    74  
    75  func (pd *pollDesc) prepareRead(isFile bool) error {
    76  	return pd.prepare('r', isFile)
    77  }
    78  
    79  func (pd *pollDesc) prepareWrite(isFile bool) error {
    80  	return pd.prepare('w', isFile)
    81  }
    82  
    83  func (pd *pollDesc) wait(mode int, isFile bool) error {
    84  	if pd.runtimeCtx == 0 {
    85  		return errors.New("waiting for unsupported file type")
    86  	}
    87  	res := runtime_pollWait(pd.runtimeCtx, mode)
    88  	return convertErr(res, isFile)
    89  }
    90  
    91  func (pd *pollDesc) waitRead(isFile bool) error {
    92  	return pd.wait('r', isFile)
    93  }
    94  
    95  func (pd *pollDesc) waitWrite(isFile bool) error {
    96  	return pd.wait('w', isFile)
    97  }
    98  
    99  func (pd *pollDesc) waitCanceled(mode int) {
   100  	if pd.runtimeCtx == 0 {
   101  		return
   102  	}
   103  	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
   104  }
   105  
   106  func (pd *pollDesc) pollable() bool {
   107  	return pd.runtimeCtx != 0
   108  }
   109  
   110  // Error values returned by runtime_pollReset and runtime_pollWait.
   111  // These must match the values in runtime/netpoll.go.
   112  const (
   113  	pollNoError        = 0
   114  	pollErrClosing     = 1
   115  	pollErrTimeout     = 2
   116  	pollErrNotPollable = 3
   117  )
   118  
   119  func convertErr(res int, isFile bool) error {
   120  	switch res {
   121  	case pollNoError:
   122  		return nil
   123  	case pollErrClosing:
   124  		return errClosing(isFile)
   125  	case pollErrTimeout:
   126  		return ErrDeadlineExceeded
   127  	case pollErrNotPollable:
   128  		return ErrNotPollable
   129  	}
   130  	println("unreachable: ", res)
   131  	panic("unreachable")
   132  }
   133  
   134  // SetDeadline sets the read and write deadlines associated with fd.
   135  func (fd *FD) SetDeadline(t time.Time) error {
   136  	return setDeadlineImpl(fd, t, 'r'+'w')
   137  }
   138  
   139  // SetReadDeadline sets the read deadline associated with fd.
   140  func (fd *FD) SetReadDeadline(t time.Time) error {
   141  	return setDeadlineImpl(fd, t, 'r')
   142  }
   143  
   144  // SetWriteDeadline sets the write deadline associated with fd.
   145  func (fd *FD) SetWriteDeadline(t time.Time) error {
   146  	return setDeadlineImpl(fd, t, 'w')
   147  }
   148  
   149  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   150  	var d int64
   151  	if !t.IsZero() {
   152  		d = int64(time.Until(t))
   153  		if d == 0 {
   154  			d = -1 // don't confuse deadline right now with no deadline
   155  		}
   156  	}
   157  	if err := fd.incref(); err != nil {
   158  		return err
   159  	}
   160  	defer fd.decref()
   161  	if fd.pd.runtimeCtx == 0 {
   162  		return ErrNoDeadline
   163  	}
   164  	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
   165  	return nil
   166  }
   167  
   168  // IsPollDescriptor reports whether fd is the descriptor being used by the poller.
   169  // This is only used for testing.
   170  func IsPollDescriptor(fd uintptr) bool {
   171  	return runtime_isPollServerDescriptor(fd)
   172  }