github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/netpoll_aix.go (about)

     1  // Copyright 2018 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  package runtime
     6  
     7  import "github.com/x04/go/src/unsafe"
     8  
     9  // This is based on the former libgo/runtime/netpoll_select.c implementation
    10  // except that it uses poll instead of select and is written in Go.
    11  // It's also based on Solaris implementation for the arming mechanisms
    12  
    13  //go:cgo_import_dynamic libc_poll poll "libc.a/shr_64.o"
    14  //go:linkname libc_poll libc_poll
    15  
    16  var libc_poll libFunc
    17  
    18  //go:nosplit
    19  func poll(pfds *pollfd, npfds uintptr, timeout uintptr) (int32, int32) {
    20  	r, err := syscall3(&libc_poll, uintptr(unsafe.Pointer(pfds)), npfds, timeout)
    21  	return int32(r), int32(err)
    22  }
    23  
    24  // pollfd represents the poll structure for AIX operating system.
    25  type pollfd struct {
    26  	fd	int32
    27  	events	int16
    28  	revents	int16
    29  }
    30  
    31  const _POLLIN = 0x0001
    32  const _POLLOUT = 0x0002
    33  const _POLLHUP = 0x2000
    34  const _POLLERR = 0x4000
    35  
    36  var (
    37  	pfds		[]pollfd
    38  	pds		[]*pollDesc
    39  	mtxpoll		mutex
    40  	mtxset		mutex
    41  	rdwake		int32
    42  	wrwake		int32
    43  	pendingUpdates	int32
    44  )
    45  
    46  func netpollinit() {
    47  	// Create the pipe we use to wakeup poll.
    48  	r, w, errno := nonblockingPipe()
    49  	if errno != 0 {
    50  		throw("netpollinit: failed to create pipe")
    51  	}
    52  	rdwake = r
    53  	wrwake = w
    54  
    55  	// Pre-allocate array of pollfd structures for poll.
    56  	pfds = make([]pollfd, 1, 128)
    57  
    58  	// Poll the read side of the pipe.
    59  	pfds[0].fd = rdwake
    60  	pfds[0].events = _POLLIN
    61  
    62  	pds = make([]*pollDesc, 1, 128)
    63  	pds[0] = nil
    64  }
    65  
    66  func netpollIsPollDescriptor(fd uintptr) bool {
    67  	return fd == uintptr(rdwake) || fd == uintptr(wrwake)
    68  }
    69  
    70  // netpollwakeup writes on wrwake to wakeup poll before any changes.
    71  func netpollwakeup() {
    72  	if pendingUpdates == 0 {
    73  		pendingUpdates = 1
    74  		b := [1]byte{0}
    75  		write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
    76  	}
    77  }
    78  
    79  func netpollopen(fd uintptr, pd *pollDesc) int32 {
    80  	lock(&mtxpoll)
    81  	netpollwakeup()
    82  
    83  	lock(&mtxset)
    84  	unlock(&mtxpoll)
    85  
    86  	pd.user = uint32(len(pfds))
    87  	pfds = append(pfds, pollfd{fd: int32(fd)})
    88  	pds = append(pds, pd)
    89  	unlock(&mtxset)
    90  	return 0
    91  }
    92  
    93  func netpollclose(fd uintptr) int32 {
    94  	lock(&mtxpoll)
    95  	netpollwakeup()
    96  
    97  	lock(&mtxset)
    98  	unlock(&mtxpoll)
    99  
   100  	for i := 0; i < len(pfds); i++ {
   101  		if pfds[i].fd == int32(fd) {
   102  			pfds[i] = pfds[len(pfds)-1]
   103  			pfds = pfds[:len(pfds)-1]
   104  
   105  			pds[i] = pds[len(pds)-1]
   106  			pds[i].user = uint32(i)
   107  			pds = pds[:len(pds)-1]
   108  			break
   109  		}
   110  	}
   111  	unlock(&mtxset)
   112  	return 0
   113  }
   114  
   115  func netpollarm(pd *pollDesc, mode int) {
   116  	lock(&mtxpoll)
   117  	netpollwakeup()
   118  
   119  	lock(&mtxset)
   120  	unlock(&mtxpoll)
   121  
   122  	switch mode {
   123  	case 'r':
   124  		pfds[pd.user].events |= _POLLIN
   125  	case 'w':
   126  		pfds[pd.user].events |= _POLLOUT
   127  	}
   128  	unlock(&mtxset)
   129  }
   130  
   131  // netpollBreak interrupts an epollwait.
   132  func netpollBreak() {
   133  	netpollwakeup()
   134  }
   135  
   136  // netpoll checks for ready network connections.
   137  // Returns list of goroutines that become runnable.
   138  // delay < 0: blocks indefinitely
   139  // delay == 0: does not block, just polls
   140  // delay > 0: block for up to that many nanoseconds
   141  //go:nowritebarrierrec
   142  func netpoll(delay int64) gList {
   143  	var timeout uintptr
   144  	if delay < 0 {
   145  		timeout = ^uintptr(0)
   146  	} else if delay == 0 {
   147  		// TODO: call poll with timeout == 0
   148  		return gList{}
   149  	} else if delay < 1e6 {
   150  		timeout = 1
   151  	} else if delay < 1e15 {
   152  		timeout = uintptr(delay / 1e6)
   153  	} else {
   154  		// An arbitrary cap on how long to wait for a timer.
   155  		// 1e9 ms == ~11.5 days.
   156  		timeout = 1e9
   157  	}
   158  retry:
   159  	lock(&mtxpoll)
   160  	lock(&mtxset)
   161  	pendingUpdates = 0
   162  	unlock(&mtxpoll)
   163  
   164  	n, e := poll(&pfds[0], uintptr(len(pfds)), timeout)
   165  	if n < 0 {
   166  		if e != _EINTR {
   167  			println("errno=", e, " len(pfds)=", len(pfds))
   168  			throw("poll failed")
   169  		}
   170  		unlock(&mtxset)
   171  		// If a timed sleep was interrupted, just return to
   172  		// recalculate how long we should sleep now.
   173  		if timeout > 0 {
   174  			return gList{}
   175  		}
   176  		goto retry
   177  	}
   178  	// Check if some descriptors need to be changed
   179  	if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   180  		if delay != 0 {
   181  			// A netpollwakeup could be picked up by a
   182  			// non-blocking poll. Only clear the wakeup
   183  			// if blocking.
   184  			var b [1]byte
   185  			for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
   186  			}
   187  		}
   188  		// Still look at the other fds even if the mode may have
   189  		// changed, as netpollBreak might have been called.
   190  		n--
   191  	}
   192  	var toRun gList
   193  	for i := 1; i < len(pfds) && n > 0; i++ {
   194  		pfd := &pfds[i]
   195  
   196  		var mode int32
   197  		if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   198  			mode += 'r'
   199  			pfd.events &= ^_POLLIN
   200  		}
   201  		if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
   202  			mode += 'w'
   203  			pfd.events &= ^_POLLOUT
   204  		}
   205  		if mode != 0 {
   206  			pds[i].everr = false
   207  			if pfd.revents == _POLLERR {
   208  				pds[i].everr = true
   209  			}
   210  			netpollready(&toRun, pds[i], mode)
   211  			n--
   212  		}
   213  	}
   214  	unlock(&mtxset)
   215  	return toRun
   216  }