...

Source file src/runtime/netpoll_aix.go

     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 "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	//go:nosplit
    25	func fcntl(fd, cmd int32, arg uintptr) int32 {
    26		r, _ := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), arg)
    27		return int32(r)
    28	}
    29	
    30	// pollfd represents the poll structure for AIX operating system.
    31	type pollfd struct {
    32		fd      int32
    33		events  int16
    34		revents int16
    35	}
    36	
    37	const _POLLIN = 0x0001
    38	const _POLLOUT = 0x0002
    39	const _POLLHUP = 0x2000
    40	const _POLLERR = 0x4000
    41	const _O_NONBLOCK = 0x4
    42	
    43	var (
    44		pfds           []pollfd
    45		pds            []*pollDesc
    46		mtxpoll        mutex
    47		mtxset         mutex
    48		rdwake         int32
    49		wrwake         int32
    50		pendingUpdates int32
    51	)
    52	
    53	func netpollinit() {
    54		var p [2]int32
    55	
    56		// Create the pipe we use to wakeup poll.
    57		if err := pipe(&p[0]); err < 0 {
    58			throw("netpollinit: failed to create pipe")
    59		}
    60		rdwake = p[0]
    61		wrwake = p[1]
    62	
    63		fl := uintptr(fcntl(rdwake, _F_GETFL, 0))
    64		fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
    65		fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
    66	
    67		fl = uintptr(fcntl(wrwake, _F_GETFL, 0))
    68		fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
    69		fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
    70	
    71		// Pre-allocate array of pollfd structures for poll.
    72		pfds = make([]pollfd, 1, 128)
    73	
    74		// Poll the read side of the pipe.
    75		pfds[0].fd = rdwake
    76		pfds[0].events = _POLLIN
    77	
    78		pds = make([]*pollDesc, 1, 128)
    79		pds[0] = nil
    80	}
    81	
    82	func netpolldescriptor() uintptr {
    83		// Both fd must be returned
    84		if rdwake > 0xFFFF || wrwake > 0xFFFF {
    85			throw("netpolldescriptor: invalid fd number")
    86		}
    87		return uintptr(rdwake<<16 | wrwake)
    88	}
    89	
    90	// netpollwakeup writes on wrwake to wakeup poll before any changes.
    91	func netpollwakeup() {
    92		if pendingUpdates == 0 {
    93			pendingUpdates = 1
    94			b := [1]byte{0}
    95			write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
    96		}
    97	}
    98	
    99	func netpollopen(fd uintptr, pd *pollDesc) int32 {
   100		lock(&mtxpoll)
   101		netpollwakeup()
   102	
   103		lock(&mtxset)
   104		unlock(&mtxpoll)
   105	
   106		pd.user = uint32(len(pfds))
   107		pfds = append(pfds, pollfd{fd: int32(fd)})
   108		pds = append(pds, pd)
   109		unlock(&mtxset)
   110		return 0
   111	}
   112	
   113	func netpollclose(fd uintptr) int32 {
   114		lock(&mtxpoll)
   115		netpollwakeup()
   116	
   117		lock(&mtxset)
   118		unlock(&mtxpoll)
   119	
   120		for i := 0; i < len(pfds); i++ {
   121			if pfds[i].fd == int32(fd) {
   122				pfds[i] = pfds[len(pfds)-1]
   123				pfds = pfds[:len(pfds)-1]
   124	
   125				pds[i] = pds[len(pds)-1]
   126				pds[i].user = uint32(i)
   127				pds = pds[:len(pds)-1]
   128				break
   129			}
   130		}
   131		unlock(&mtxset)
   132		return 0
   133	}
   134	
   135	func netpollarm(pd *pollDesc, mode int) {
   136		lock(&mtxpoll)
   137		netpollwakeup()
   138	
   139		lock(&mtxset)
   140		unlock(&mtxpoll)
   141	
   142		switch mode {
   143		case 'r':
   144			pfds[pd.user].events |= _POLLIN
   145		case 'w':
   146			pfds[pd.user].events |= _POLLOUT
   147		}
   148		unlock(&mtxset)
   149	}
   150	
   151	//go:nowritebarrierrec
   152	func netpoll(block bool) gList {
   153		timeout := ^uintptr(0)
   154		if !block {
   155			timeout = 0
   156			return gList{}
   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			goto retry
   172		}
   173		// Check if some descriptors need to be changed
   174		if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   175			var b [1]byte
   176			for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
   177			}
   178			// Do not look at the other fds in this case as the mode may have changed
   179			// XXX only additions of flags are made, so maybe it is ok
   180			unlock(&mtxset)
   181			goto retry
   182		}
   183		var toRun gList
   184		for i := 0; i < len(pfds) && n > 0; i++ {
   185			pfd := &pfds[i]
   186	
   187			var mode int32
   188			if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   189				mode += 'r'
   190				pfd.events &= ^_POLLIN
   191			}
   192			if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
   193				mode += 'w'
   194				pfd.events &= ^_POLLOUT
   195			}
   196			if mode != 0 {
   197				pds[i].everr = false
   198				if pfd.revents == _POLLERR {
   199					pds[i].everr = true
   200				}
   201				netpollready(&toRun, pds[i], mode)
   202				n--
   203			}
   204		}
   205		unlock(&mtxset)
   206		if block && toRun.empty() {
   207			goto retry
   208		}
   209		return toRun
   210	}
   211	

View as plain text