fd_poll_runtime.mx raw

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