Refactor linux driver to use poll instead of select

This commit is contained in:
2022-01-06 18:51:24 -05:00
parent 860b6f60b1
commit b23145a4a4

View File

@@ -325,25 +325,47 @@ public:
} }
void handle_socket_input_output(int mstimeout) { void handle_socket_input_output(int mstimeout) {
fd_set rfds, wfds, efds; // Construct the pollfd vector.
int nbytes; const char *bytes; std::vector<struct pollfd> pollvec;
int nfds = calc_select_sets(rfds, wfds, efds); pollvec.resize(listen_sockets_.size() + chans_.size() + 1);
struct timeval timeout; int index = 0;
timeout.tv_sec = mstimeout / 1000; for (const auto &p : listen_sockets_) {
timeout.tv_usec = (mstimeout - (timeout.tv_sec*1000)) * 1000; struct pollfd &pfd = pollvec[index++];
int status = select(nfds, &rfds, &wfds, &efds, &timeout); pfd.fd = p.second;
pfd.events = POLLIN;
}
for (const ChanInfo &chan : chans_) {
struct pollfd &pfd = pollvec[index++];
pfd.fd = chan.socket;
pfd.events = POLLIN;
if (!driven_->drv_outgoing_empty(chan.chid)) {
pfd.events |= POLLOUT;
}
}
struct pollfd &stdiopoll = pollvec[index++];
stdiopoll.fd = 0;
stdiopoll.events = POLLIN;
// Do the poll.
int status = poll(&pollvec[0], pollvec.size(), mstimeout);
assert(status >= 0); assert(status >= 0);
// Check listening sockets.
index = 0;
for (auto &p : listen_sockets_) { for (auto &p : listen_sockets_) {
if (FD_ISSET(p.second, &rfds) || FD_ISSET(p.second, &efds)) { struct pollfd &pfd = pollvec[index++];
if (pfd.revents & (POLLIN | POLLERR)) {
accept_connections(p.first, p.second); accept_connections(p.first, p.second);
} }
} }
// Transfer bytes wherever possible.
for (ChanInfo &chan : chans_) { for (ChanInfo &chan : chans_) {
struct pollfd &pfd = pollvec[index++];
SOCKET sock = chan.socket; SOCKET sock = chan.socket;
if (sock == INVALID_SOCKET) continue; if (sock == INVALID_SOCKET) continue;
if (FD_ISSET(sock, &wfds)) { if (pfd.revents & POLLOUT) {
int nbytes; const char *bytes;
chan.state = CHAN_OPEN; chan.state = CHAN_OPEN;
driven_->drv_peek_outgoing(chan.chid, &nbytes, &bytes); driven_->drv_peek_outgoing(chan.chid, &nbytes, &bytes);
if (nbytes > 0) { if (nbytes > 0) {
@@ -356,7 +378,7 @@ public:
} }
} }
} }
if (FD_ISSET(sock, &rfds) || FD_ISSET(sock, &efds)) { if (pfd.revents & (POLLIN | POLLERR)) {
// Someday, find a way to avoid this copy. // Someday, find a way to avoid this copy.
int nrecv = recv(sock, chbuf.get(), 65536, 0); int nrecv = recv(sock, chbuf.get(), 65536, 0);
if (nrecv <= 0) { if (nrecv <= 0) {
@@ -368,6 +390,8 @@ public:
} }
} }
} }
// Delete any newly-inactive channels
cleanup_channels(); cleanup_channels();
} }