static void handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty) { int32 mode; if(op == nil) runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil"); mode = op->mode; if(mode != 'r' && mode != 'w') { runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode); runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode"); } op->errno = errno; op->qty = qty; runtime·netpollready(gpp, op->pd, mode); }
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; }
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, mode); } if(block && gp == nil) goto retry; return gp; }
runtime·netpoll(bool block) { static int32 lasterr; PortEvent events[128], *ev; PollDesc *pd; int32 i, mode, clear; uint32 n; Timespec *wait = nil, zero; G *gp; if(portfd == -1) return (nil); if(!block) { zero.tv_sec = 0; zero.tv_nsec = 0; wait = &zero; } retry: n = 1; if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) { if(errno != EINTR && errno != lasterr) { lasterr = errno; runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno); } goto retry; } gp = nil; for(i = 0; i < n; i++) { ev = &events[i]; if(ev->portev_events == 0) continue; pd = (PollDesc *)ev->portev_user; mode = 0; clear = 0; if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) { mode += 'r'; clear |= POLLIN; } if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) { mode += 'w'; clear |= POLLOUT; } // To effect edge-triggered events, we need to be sure to // update our association with whatever events were not // set with the event. For example if we are registered // for POLLIN|POLLOUT, and we get POLLIN, besides waking // the goroutine interested in POLLIN we have to not forget // about the one interested in POLLOUT. if(clear != 0) { runtime·netpolllock(pd); runtime·netpollupdate(pd, 0, clear); runtime·netpollunlock(pd); } if(mode) runtime·netpollready(&gp, pd, mode); } if(block && gp == nil) goto retry; return gp; }