static void fdevent_process() { std::vector<pollfd> pollfds; for (auto it = g_poll_node_map.begin(); it != g_poll_node_map.end(); ++it) { pollfds.push_back(it->second.pollfd); } CHECK_GT(pollfds.size(), 0u); D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str()); int ret = TEMP_FAILURE_RETRY(poll(&pollfds[0], pollfds.size(), -1)); if (ret == -1) { PLOG(ERROR) << "poll(), ret = " << ret; return; } for (auto& pollfd : pollfds) { if (pollfd.revents != 0) { D("for fd %d, revents = %x", pollfd.fd, pollfd.revents); } unsigned events = 0; if (pollfd.revents & POLLIN) { events |= FDE_READ; } if (pollfd.revents & POLLOUT) { events |= FDE_WRITE; } if (pollfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { // We fake a read, as the rest of the code assumes that errors will // be detected at that point. events |= FDE_READ | FDE_ERROR; } #if defined(__linux__) if (pollfd.revents & POLLRDHUP) { events |= FDE_READ | FDE_ERROR; } #endif if (events != 0) { auto it = g_poll_node_map.find(pollfd.fd); CHECK(it != g_poll_node_map.end()); fdevent* fde = it->second.fde; CHECK_EQ(fde->fd, pollfd.fd); fde->events |= events; D("%s got events %x", dump_fde(fde).c_str(), events); fde->state |= FDE_PENDING; g_pending_list.push_back(fde); } } }
/* Wrap around select */ int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout) { int n, ret; int i, fd; struct timeval _timeo, *timeo = NULL; fd_set rfds, wfds, efds; int max_fd = -1; DEBUG("poll("); dump_pollfds(_pfd, _nfds, _timeout); DEBUG(")\n"); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); n = 0; for (i = 0; i < _nfds; i++) { fd = _pfd[i].fd; _pfd[i].revents = 0; /* fd < 0, revents = 0, which is already set */ if (fd < 0) continue; /* fd is invalid, revents = POLLNVAL, increment counter */ if (fd >= NOFILE || files[fd].type == FTYPE_NONE) { n++; _pfd[i].revents |= POLLNVAL; continue; } /* normal case, map POLL* into readfds and writefds: * POLLIN -> readfds * POLLOUT -> writefds * POLL* -> none */ if (_pfd[i].events & POLLIN) FD_SET(fd, &rfds); if (_pfd[i].events & POLLOUT) FD_SET(fd, &wfds); /* always set exceptfds */ FD_SET(fd, &efds); if (fd > max_fd) max_fd = fd; } /* should never sleep when we already have events */ if (n) { _timeo.tv_sec = 0; _timeo.tv_usec = 0; timeo = &_timeo; } else if (_timeout >= 0) { /* normal case, construct _timeout, might sleep */ _timeo.tv_sec = _timeout / 1000; _timeo.tv_usec = (_timeout % 1000) * 1000; timeo = &_timeo; } else { /* _timeout < 0, block forever */ timeo = NULL; } ret = select(max_fd+1, &rfds, &wfds, &efds, timeo); /* error in select, just return, errno is set by select() */ if (ret < 0) return ret; for (i = 0; i < _nfds; i++) { fd = _pfd[i].fd; /* the revents has already been set for all error case */ if (fd < 0 || fd >= NOFILE || files[fd].type == FTYPE_NONE) continue; if (FD_ISSET(fd, &rfds) || FD_ISSET(fd, &wfds) || FD_ISSET(fd, &efds)) n++; if (FD_ISSET(fd, &efds)) { /* anything bad happens we set POLLERR */ _pfd[i].revents |= POLLERR; continue; } if (FD_ISSET(fd, &rfds)) _pfd[i].revents |= POLLIN; if (FD_ISSET(fd, &wfds)) _pfd[i].revents |= POLLOUT; } return n; }
void httpd_main(void) { int rv, n, t, accepting; time_t hours, last_time; accepting = 1; last_time = current_time = startuptime = time(0); hours = current_time / 3600; log_d("*** %s starting", server_version); while (gotsigterm == 0) { if (gotsighup) { gotsighup = 0; init_logs(0); if (debug) log_d("logs reopened"); } if (gotsigusr1) { gotsigusr1 = 0; close_connections(); log_d("connections closed"); } if (gotsigusr2) { gotsigusr2 = 0; close_servers(); log_d("servers closed"); } if (gotsigchld) { gotsigchld = 0; reap_children(); } if (gotsigquit) { gotsigquit = 0; debug = debug == 0; if (debug) log_d("debugging turned on"); else log_d("debugging turned off"); } if (gotsigwinch) { gotsigwinch = 0; log_d("performing internal dump"); internal_dump(); } n = 0; if (accepting && find_connection()) n = setup_server_pollfds(n); n = setup_connection_pollfds(n); n = setup_child_pollfds(n, forked_connections.head); if (n == 0 && accepting && stats.nconnections == 0) { log_d("no more sockets to poll from"); break; } t = accepting ? 60000 : 1000; if (debug) dump_pollfds(n, 0); rv = poll(pollfds, n, t); current_time = time(0); if (rv == -1) { if (errno != EINTR) { lerror("poll"); break; } else { if (debug) log_d("poll interrupted"); continue; } } if (debug) dump_pollfds(n, 1); if (current_time != last_time) { if (accepting == 0) accepting = 1; if (current_time / 3600 != hours) { hours = current_time / 3600; init_logs(0); if (debug) log_d("logs rotated"); } } if (rv) { if (accepting && run_servers() == -1) accepting = 0; run_connections(); } if (current_time != last_time) { cleanup_connections(); last_time = current_time; } } log_d("*** shutting down"); }