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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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()/
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user