// Polls for ready network connections. // Returns list of goroutines that become runnable. G* runtime_netpoll(bool block) { static int32 lasterr; Kevent events[64], *ev; Timespec ts, *tp; int32 n, i, mode; G *gp; if(kq == -1) return nil; tp = nil; if(!block) { ts.tv_sec = 0; ts.tv_nsec = 0; tp = &ts; } gp = nil; retry: n = runtime_kevent(kq, nil, 0, events, nelem(events), tp); if(n < 0) { if(n != -EINTR && n != lasterr) { lasterr = n; runtime_printf("runtime: kevent on fd %d failed with %d\n", kq, -n); } goto retry; } for(i = 0; i < n; i++) { ev = &events[i]; mode = 0; if(ev->filter == EVFILT_READ) mode += 'r'; if(ev->filter == EVFILT_WRITE) mode += 'w'; if(mode) runtime_netpollready(&gp, (PollDesc*)ev->udata, mode); } if(block && gp == nil) goto retry; return gp; }
// polls for ready network connections // returns list of goroutines that become runnable G* runtime_netpoll(bool block) { static int32 lasterr; EpollEvent events[128], *ev; int32 n, i, waitms, mode; G *gp; if(epfd == -1) return nil; waitms = -1; if(!block) waitms = 0; retry: n = runtime_epollwait(epfd, events, nelem(events), waitms); if(n < 0) { if(n != -EINTR && n != lasterr) { lasterr = n; runtime_printf("runtime: epollwait on fd %d failed with %d\n", epfd, -n); } goto retry; } gp = nil; for(i = 0; i < n; i++) { ev = &events[i]; if(ev->events == 0) continue; mode = 0; if(ev->events & (EPOLLIN|EPOLLRDHUP|EPOLLHUP|EPOLLERR)) mode += 'r'; if(ev->events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) mode += 'w'; if(mode) runtime_netpollready(&gp, (void*)ev->data.ptr, mode); } if(block && gp == nil) goto retry; return gp; }
G* runtime_netpoll(bool block) { fd_set *prfds, *pwfds, *pefds, *ptfds; bool allocatedfds; struct timeval timeout; struct timeval *pt; int max, c, i; G *gp; int32 mode; byte b; struct stat st; retry: runtime_lock(&selectlock); max = allocated; if(max == 0) { runtime_unlock(&selectlock); return nil; } if(inuse) { prfds = runtime_SysAlloc(4 * sizeof fds, &mstats.other_sys); pwfds = prfds + 1; pefds = pwfds + 1; ptfds = pefds + 1; allocatedfds = true; } else { prfds = &grfds; pwfds = &gwfds; pefds = &gefds; ptfds = >fds; inuse = true; allocatedfds = false; } __builtin_memcpy(prfds, &fds, sizeof fds); runtime_unlock(&selectlock); __builtin_memcpy(pwfds, prfds, sizeof fds); FD_CLR(rdwake, pwfds); __builtin_memcpy(pefds, pwfds, sizeof fds); __builtin_memcpy(ptfds, pwfds, sizeof fds); __builtin_memset(&timeout, 0, sizeof timeout); pt = &timeout; if(block) pt = nil; c = select(max, prfds, pwfds, pefds, pt); if(c < 0) { if(errno == EBADF) { // Some file descriptor has been closed. // Check each one, and treat each closed // descriptor as ready for read/write. c = 0; FD_ZERO(prfds); FD_ZERO(pwfds); FD_ZERO(pefds); for(i = 0; i < max; i++) { if(FD_ISSET(i, ptfds) && fstat(i, &st) < 0 && errno == EBADF) { FD_SET(i, prfds); FD_SET(i, pwfds); c += 2; } } } else { if(errno != EINTR) runtime_printf("runtime: select failed with %d\n", errno); goto retry; } } gp = nil; for(i = 0; i < max && c > 0; i++) { mode = 0; if(FD_ISSET(i, prfds)) { mode += 'r'; --c; } if(FD_ISSET(i, pwfds)) { mode += 'w'; --c; } if(FD_ISSET(i, pefds)) { mode = 'r' + 'w'; --c; } if(i == rdwake) { while(read(rdwake, &b, sizeof b) > 0) ; continue; } if(mode) { PollDesc *pd; runtime_lock(&selectlock); pd = data[i]; runtime_unlock(&selectlock); if(pd != nil) runtime_netpollready(&gp, pd, mode); } } if(block && gp == nil) goto retry; if(allocatedfds) { runtime_SysFree(prfds, 4 * sizeof fds, &mstats.other_sys); } else { runtime_lock(&selectlock); inuse = false; runtime_unlock(&selectlock); } return gp; }