Skip to content

Commit b53d39a

Browse files
committed
Our select() function is emulated using poll(), which is a sensible thing
to do. However, it did several things wrong that this patch fixes. Thanks to Paolo Bonzini for finding these problems (see issue #35). 1. When poll() returned a bare POLLHUP, without POLLIN, our select() didn't return a read event. But nothing in the manpages guarantees that POLLHUP is accompanied by POLLIN, and some special file implementations might forget it. As an example, in Linux POLLHUP without POLLIN is common. But POLLHUP on its own already means that there's nothing more to read, so a read() will return immediately without blocking - and therefore select() needs to turn on the readable bit for this fd. 2. Similarly, a bare POLLRDHUP should turn on the writable bit: The reader on this file hug up, so a write will fail immediately. 3. Our poll() and select() confused what POLLERR means. POLLERR does not mean poll() found a bad file descriptor - there is POLLNVAL for that. So this patch fixes poll() to set POLLNVAL, not POLLERR, and select() to return with errno=EBADF when it sees POLLNVAL, not POLLERR. 4. Rather, POLLERR means the file descriptor is in an error state, so every read() or write() will return immediately (with an error). So when we see it, we need to turn on both read and write bits in this case. 5. The meaning of "exceptfds" isn't clear in any manual page, and it seems there're a lot of opinions on what it might mean. In this patch I did what Paolo suggested, which is to set the except bit when POLLPRI. (I don't set exceptfds on POLLERR, or any other case). Signed-off-by: Nadav Har'El <nyh@cloudius-systems.com>
1 parent ea4cb9f commit b53d39a

File tree

2 files changed

+17
-12
lines changed

2 files changed

+17
-12
lines changed

core/poll.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ int poll_scan(struct pollfd _pfd[], nfds_t _nfds)
121121

122122
error = fget(entry->fd, &fp);
123123
if (error) {
124-
entry->revents |= POLLERR;
124+
entry->revents |= POLLNVAL;
125125
nr_events++;
126126
continue;
127127
}

core/select.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,30 +115,35 @@ int select (int nfds,
115115
for (i=0; i < poll_fd_idx; i++) {
116116
if (req[i].revents == 0)
117117
continue;
118-
118+
if (req[i].revents & POLLNVAL) {
119+
errno = EBADF;
120+
error = -1;
121+
break;
122+
}
123+
bool event = false;
119124
if (readfds) {
120-
if (req[i].revents & POLLIN) {
125+
if (req[i].revents & (POLLIN | POLLHUP | POLLERR)) {
121126
FD_SET(req[i].fd, readfds);
122-
num_fds++;
127+
event = true;
123128
}
124129
}
125130

126131
if (writefds) {
127-
if (req[i].revents & POLLOUT) {
132+
if (req[i].revents & (POLLOUT | POLLRDHUP | POLLERR)) {
128133
FD_SET(req[i].fd, writefds);
129-
num_fds++;
134+
event = true;
130135
}
131136
}
132137

133-
if (req[i].revents & POLLERR) {
134-
if (exceptfds) {
138+
if (exceptfds) {
139+
if (req[i].revents & POLLPRI) {
135140
FD_SET(req[i].fd, exceptfds);
136-
num_fds++;
141+
event = true;
137142
}
143+
}
138144

139-
errno = EBADF;
140-
error = -1;
141-
break;
145+
if (event) {
146+
num_fds++;
142147
}
143148
}
144149

0 commit comments

Comments
 (0)