Source file src/internal/poll/fd_poll_runtime.go

     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  	if fd.pd.runtimeCtx == 0 {
   159  		return ErrNoDeadline
   160  	}
   161  	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
   162  	return nil
   163  }
   164  
   165  // IsPollDescriptor reports whether fd is the descriptor being used by the poller.
   166  // This is only used for testing.
   167  //
   168  // IsPollDescriptor should be an internal detail,
   169  // but widely used packages access it using linkname.
   170  // Notable members of the hall of shame include:
   171  //   - github.com/opencontainers/runc
   172  //
   173  // Do not remove or change the type signature.
   174  // See go.dev/issue/67401.
   175  //
   176  //go:linkname IsPollDescriptor
   177  func IsPollDescriptor(fd uintptr) bool {
   178  	return runtime_isPollServerDescriptor(fd)
   179  }
   180  

View as plain text