github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 "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  const pollVerbose = false
    54  
    55  func netpollinit() {
    56  	var p [2]int32
    57  
    58  	// Create the pipe we use to wakeup poll.
    59  	if err := pipe(&p[0]); err < 0 {
    60  		throw("netpollinit: failed to create pipe")
    61  	}
    62  	rdwake = p[0]
    63  	wrwake = p[1]
    64  
    65  	fl := uintptr(fcntl(rdwake, _F_GETFL, 0))
    66  	fcntl(rdwake, _F_SETFL, fl|_O_NONBLOCK)
    67  	fcntl(rdwake, _F_SETFD, _FD_CLOEXEC)
    68  
    69  	fl = uintptr(fcntl(wrwake, _F_GETFL, 0))
    70  	fcntl(wrwake, _F_SETFL, fl|_O_NONBLOCK)
    71  	fcntl(wrwake, _F_SETFD, _FD_CLOEXEC)
    72  
    73  	// Pre-allocate array of pollfd structures for poll.
    74  	if pollVerbose {
    75  		println("*** allocating")
    76  	}
    77  	pfds = make([]pollfd, 1, 128)
    78  	if pollVerbose {
    79  		println("*** allocating done", &pfds[0])
    80  	}
    81  
    82  	// Poll the read side of the pipe.
    83  	pfds[0].fd = rdwake
    84  	pfds[0].events = _POLLIN
    85  
    86  	pds = make([]*pollDesc, 1, 128)
    87  	pds[0] = nil
    88  }
    89  
    90  func netpolldescriptor() uintptr {
    91  	// Both fd must be returned
    92  	if rdwake > 0xFFFF || wrwake > 0xFFFF {
    93  		throw("netpolldescriptor: invalid fd number")
    94  	}
    95  	return uintptr(rdwake<<16 | wrwake)
    96  }
    97  
    98  // netpollwakeup writes on wrwake to wakeup poll before any changes.
    99  func netpollwakeup() {
   100  	if pendingUpdates == 0 {
   101  		pendingUpdates = 1
   102  		if pollVerbose {
   103  			println("*** writing 1 byte")
   104  		}
   105  		b := [1]byte{0}
   106  		write(uintptr(wrwake), unsafe.Pointer(&b[0]), 1)
   107  	}
   108  }
   109  
   110  func netpollopen(fd uintptr, pd *pollDesc) int32 {
   111  	if pollVerbose {
   112  		println("*** netpollopen", fd)
   113  	}
   114  	lock(&mtxpoll)
   115  	netpollwakeup()
   116  
   117  	lock(&mtxset)
   118  	unlock(&mtxpoll)
   119  
   120  	pd.user = uint32(len(pfds))
   121  	pfds = append(pfds, pollfd{fd: int32(fd)})
   122  	pds = append(pds, pd)
   123  	unlock(&mtxset)
   124  	return 0
   125  }
   126  
   127  func netpollclose(fd uintptr) int32 {
   128  	if pollVerbose {
   129  		println("*** netpollclose", fd)
   130  	}
   131  	lock(&mtxpoll)
   132  	netpollwakeup()
   133  
   134  	lock(&mtxset)
   135  	unlock(&mtxpoll)
   136  
   137  	for i := 0; i < len(pfds); i++ {
   138  		if pfds[i].fd == int32(fd) {
   139  			pfds[i] = pfds[len(pfds)-1]
   140  			pfds = pfds[:len(pfds)-1]
   141  
   142  			pds[i] = pds[len(pds)-1]
   143  			pds[i].user = uint32(i)
   144  			pds = pds[:len(pds)-1]
   145  			break
   146  		}
   147  	}
   148  	unlock(&mtxset)
   149  	return 0
   150  }
   151  
   152  func netpollarm(pd *pollDesc, mode int) {
   153  	if pollVerbose {
   154  		println("*** netpollarm", pd.fd, mode)
   155  	}
   156  	lock(&mtxpoll)
   157  	netpollwakeup()
   158  
   159  	lock(&mtxset)
   160  	unlock(&mtxpoll)
   161  
   162  	switch mode {
   163  	case 'r':
   164  		pfds[pd.user].events |= _POLLIN
   165  	case 'w':
   166  		pfds[pd.user].events |= _POLLOUT
   167  	}
   168  	unlock(&mtxset)
   169  }
   170  
   171  //go:nowritebarrierrec
   172  func netpoll(block bool) gList {
   173  	timeout := ^uintptr(0)
   174  	if !block {
   175  		timeout = 0
   176  		return gList{}
   177  	}
   178  	if pollVerbose {
   179  		println("*** netpoll", block)
   180  	}
   181  retry:
   182  	lock(&mtxpoll)
   183  	lock(&mtxset)
   184  	pendingUpdates = 0
   185  	unlock(&mtxpoll)
   186  
   187  	if pollVerbose {
   188  		println("*** netpoll before poll")
   189  	}
   190  	n, e := poll(&pfds[0], uintptr(len(pfds)), timeout)
   191  	if pollVerbose {
   192  		println("*** netpoll after poll", n)
   193  	}
   194  	if n < 0 {
   195  		if e != _EINTR {
   196  			println("errno=", e, " len(pfds)=", len(pfds))
   197  			throw("poll failed")
   198  		}
   199  		if pollVerbose {
   200  			println("*** poll failed")
   201  		}
   202  		unlock(&mtxset)
   203  		goto retry
   204  	}
   205  	// Check if some descriptors need to be changed
   206  	if n != 0 && pfds[0].revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   207  		var b [1]byte
   208  		for read(rdwake, unsafe.Pointer(&b[0]), 1) == 1 {
   209  			if pollVerbose {
   210  				println("*** read 1 byte from pipe")
   211  			}
   212  		}
   213  		// Do not look at the other fds in this case as the mode may have changed
   214  		// XXX only additions of flags are made, so maybe it is ok
   215  		unlock(&mtxset)
   216  		goto retry
   217  	}
   218  	var toRun gList
   219  	for i := 0; i < len(pfds) && n > 0; i++ {
   220  		pfd := &pfds[i]
   221  
   222  		var mode int32
   223  		if pfd.revents&(_POLLIN|_POLLHUP|_POLLERR) != 0 {
   224  			mode += 'r'
   225  			pfd.events &= ^_POLLIN
   226  		}
   227  		if pfd.revents&(_POLLOUT|_POLLHUP|_POLLERR) != 0 {
   228  			mode += 'w'
   229  			pfd.events &= ^_POLLOUT
   230  		}
   231  		if mode != 0 {
   232  			if pollVerbose {
   233  				println("*** netpollready i=", i, "revents=", pfd.revents, "events=", pfd.events, "pd=", pds[i])
   234  			}
   235  			netpollready(&toRun, pds[i], mode)
   236  			n--
   237  		}
   238  	}
   239  	unlock(&mtxset)
   240  	if block && toRun.empty() {
   241  		goto retry
   242  	}
   243  	if pollVerbose {
   244  		println("*** netpoll returning end")
   245  	}
   246  	return toRun
   247  }