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 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  		return errnoErr(syscall.Errno(errno))
    42  	}
    43  	pd.runtimeCtx = ctx
    44  	return nil
    45  }
    46  
    47  func (pd *pollDesc) close() {
    48  	if pd.runtimeCtx == 0 {
    49  		return
    50  	}
    51  	runtime_pollClose(pd.runtimeCtx)
    52  	pd.runtimeCtx = 0
    53  }
    54  
    55  // Evict evicts fd from the pending list, unblocking any I/O running on fd.
    56  func (pd *pollDesc) evict() {
    57  	if pd.runtimeCtx == 0 {
    58  		return
    59  	}
    60  	runtime_pollUnblock(pd.runtimeCtx)
    61  }
    62  
    63  func (pd *pollDesc) prepare(mode int, isFile bool) error {
    64  	if pd.runtimeCtx == 0 {
    65  		return nil
    66  	}
    67  	res := runtime_pollReset(pd.runtimeCtx, mode)
    68  	return convertErr(res, isFile)
    69  }
    70  
    71  func (pd *pollDesc) prepareRead(isFile bool) error {
    72  	return pd.prepare('r', isFile)
    73  }
    74  
    75  func (pd *pollDesc) prepareWrite(isFile bool) error {
    76  	return pd.prepare('w', isFile)
    77  }
    78  
    79  func (pd *pollDesc) wait(mode int, isFile bool) error {
    80  	if pd.runtimeCtx == 0 {
    81  		return errors.New("waiting for unsupported file type")
    82  	}
    83  	res := runtime_pollWait(pd.runtimeCtx, mode)
    84  	return convertErr(res, isFile)
    85  }
    86  
    87  func (pd *pollDesc) waitRead(isFile bool) error {
    88  	return pd.wait('r', isFile)
    89  }
    90  
    91  func (pd *pollDesc) waitWrite(isFile bool) error {
    92  	return pd.wait('w', isFile)
    93  }
    94  
    95  func (pd *pollDesc) waitCanceled(mode int) {
    96  	if pd.runtimeCtx == 0 {
    97  		return
    98  	}
    99  	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
   100  }
   101  
   102  func (pd *pollDesc) pollable() bool {
   103  	return pd.runtimeCtx != 0
   104  }
   105  
   106  // Error values returned by runtime_pollReset and runtime_pollWait.
   107  // These must match the values in runtime/netpoll.go.
   108  const (
   109  	pollNoError        = 0
   110  	pollErrClosing     = 1
   111  	pollErrTimeout     = 2
   112  	pollErrNotPollable = 3
   113  )
   114  
   115  func convertErr(res int, isFile bool) error {
   116  	switch res {
   117  	case pollNoError:
   118  		return nil
   119  	case pollErrClosing:
   120  		return errClosing(isFile)
   121  	case pollErrTimeout:
   122  		return ErrDeadlineExceeded
   123  	case pollErrNotPollable:
   124  		return ErrNotPollable
   125  	}
   126  	println("unreachable: ", res)
   127  	panic("unreachable")
   128  }
   129  
   130  // SetDeadline sets the read and write deadlines associated with fd.
   131  func (fd *FD) SetDeadline(t time.Time) error {
   132  	return setDeadlineImpl(fd, t, 'r'+'w')
   133  }
   134  
   135  // SetReadDeadline sets the read deadline associated with fd.
   136  func (fd *FD) SetReadDeadline(t time.Time) error {
   137  	return setDeadlineImpl(fd, t, 'r')
   138  }
   139  
   140  // SetWriteDeadline sets the write deadline associated with fd.
   141  func (fd *FD) SetWriteDeadline(t time.Time) error {
   142  	return setDeadlineImpl(fd, t, 'w')
   143  }
   144  
   145  func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
   146  	var d int64
   147  	if !t.IsZero() {
   148  		d = int64(time.Until(t))
   149  		if d == 0 {
   150  			d = -1 // don't confuse deadline right now with no deadline
   151  		}
   152  	}
   153  	if err := fd.incref(); err != nil {
   154  		return err
   155  	}
   156  	defer fd.decref()
   157  	if fd.pd.runtimeCtx == 0 {
   158  		return ErrNoDeadline
   159  	}
   160  	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
   161  	return nil
   162  }
   163  
   164  // IsPollDescriptor reports whether fd is the descriptor being used by the poller.
   165  // This is only used for testing.
   166  func IsPollDescriptor(fd uintptr) bool {
   167  	return runtime_isPollServerDescriptor(fd)
   168  }
   169  

View as plain text