kernel: Properly report that no events were selected in select_fd.

Adjust wait_for_objects/select/poll implementations to handle this
properly (use the original array's selected-events values, not
the select info's values, and ignore errors if events were reported.)

event_queue is not adjusted and will behave differently after this
change (specifically it will not allow such FDs to be added,
which matches behavior of epoll/kqueue elsewhere.)

Change-Id: Icea26efce894f00697afd29f3bf51b7e60e522ab
This commit is contained in:
Augustin Cavalier
2024-07-16 15:32:59 -04:00
parent 9aaf80afaa
commit 7f86e9ee17
4 changed files with 23 additions and 19 deletions
+2 -4
View File
@@ -1615,9 +1615,8 @@ devfs_select(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
// If the device has no select() hook, notify select() now.
if (!vnode->stream.u.dev.device->HasSelect()) {
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
return notify_select_event((selectsync*)sync, event);
else
return B_OK;
notify_select_event((selectsync*)sync, event);
return B_UNSUPPORTED;
}
return vnode->stream.u.dev.device->Select(cookie->device_cookie, event,
@@ -1635,7 +1634,6 @@ devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie,
if (!S_ISCHR(vnode->stream.type))
return B_NOT_ALLOWED;
// If the device has no select() hook, notify select() now.
if (!vnode->stream.u.dev.device->HasDeselect())
return B_OK;
+15 -9
View File
@@ -535,7 +535,7 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
fd_zero(errorSet, numFDs);
if (status == B_OK) {
for (count = 0, fd = 0;fd < numFDs; fd++) {
for (count = 0, fd = 0; fd < numFDs; fd++) {
if (readSet && sync->set[fd].events & (SELECT_FLAG(B_SELECT_READ)
| SELECT_FLAG(B_SELECT_DISCONNECTED) | SELECT_FLAG(B_SELECT_ERROR))) {
FD_SET(fd, readSet);
@@ -584,12 +584,16 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout,
int fd = fds[i].fd;
// initialize events masks
sync->set[i].selected_events = fds[i].events
| POLLNVAL | POLLERR | POLLHUP;
fds[i].events |= POLLNVAL | POLLERR | POLLHUP;
sync->set[i].selected_events = fds[i].events;
sync->set[i].events = 0;
fds[i].revents = 0;
if (fd >= 0 && select_fd(fd, sync->set + i, kernel) != B_OK) {
// If the FD returned events as well as an error, ignore the error.
if (sync->set[i].events != 0)
continue;
sync->set[i].events = POLLNVAL;
fds[i].revents = POLLNVAL;
// indicates that the FD doesn't need to be deselected
@@ -634,8 +638,7 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout,
continue;
// POLLxxx flags and B_SELECT_xxx flags are compatible
fds[i].revents = sync->set[i].events
& sync->set[i].selected_events;
fds[i].revents = sync->set[i].events & fds[i].events;
if (fds[i].revents != 0)
count++;
}
@@ -676,12 +679,16 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
int32 object = infos[i].object;
// initialize events masks
sync->set[i].selected_events = infos[i].events
| B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
infos[i].events |= B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
sync->set[i].selected_events = infos[i].events;
sync->set[i].events = 0;
infos[i].events = 0;
if (select_object(type, object, sync->set + i, kernel) != B_OK) {
// If the object returned events as well as an error, ignore the error.
if (sync->set[i].events != 0)
continue;
sync->set[i].events = B_EVENT_INVALID;
infos[i].events = B_EVENT_INVALID;
// indicates that the object doesn't need to be deselected
@@ -708,8 +715,7 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
ssize_t count = 0;
if (status == B_OK) {
for (int i = 0; i < numInfos; i++) {
infos[i].events = sync->set[i].events
& sync->set[i].selected_events;
infos[i].events &= sync->set[i].events;
if (infos[i].events != 0)
count++;
}
+4 -3
View File
@@ -562,9 +562,10 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
// immediately notify the select call
eventsToSelect &= ~SELECT_OUTPUT_ONLY_FLAGS;
if (eventsToSelect != 0)
return notify_select_events(info, eventsToSelect);
else
return B_OK;
notify_select_events(info, eventsToSelect);
info->selected_events = 0;
return B_UNSUPPORTED;
}
// We need the FD to stay open while we're doing this, so no select()/
+2 -3
View File
@@ -5847,9 +5847,8 @@ file_select(struct file_descriptor* descriptor, uint8 event,
// If the FS has no select() hook, notify select() now.
if (!HAS_FS_CALL(vnode, select)) {
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
return notify_select_event(sync, event);
else
return B_OK;
notify_select_event(sync, event);
return B_UNSUPPORTED;
}
return FS_CALL(vnode, select, descriptor->cookie, event, sync);