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 the device has no select() hook, notify select() now.
|
||||||
if (!vnode->stream.u.dev.device->HasSelect()) {
|
if (!vnode->stream.u.dev.device->HasSelect()) {
|
||||||
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
|
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
|
||||||
return notify_select_event((selectsync*)sync, event);
|
notify_select_event((selectsync*)sync, event);
|
||||||
else
|
return B_UNSUPPORTED;
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vnode->stream.u.dev.device->Select(cookie->device_cookie, event,
|
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))
|
if (!S_ISCHR(vnode->stream.type))
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
// If the device has no select() hook, notify select() now.
|
|
||||||
if (!vnode->stream.u.dev.device->HasDeselect())
|
if (!vnode->stream.u.dev.device->HasDeselect())
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
|
|||||||
@@ -535,7 +535,7 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
|||||||
fd_zero(errorSet, numFDs);
|
fd_zero(errorSet, numFDs);
|
||||||
|
|
||||||
if (status == B_OK) {
|
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)
|
if (readSet && sync->set[fd].events & (SELECT_FLAG(B_SELECT_READ)
|
||||||
| SELECT_FLAG(B_SELECT_DISCONNECTED) | SELECT_FLAG(B_SELECT_ERROR))) {
|
| SELECT_FLAG(B_SELECT_DISCONNECTED) | SELECT_FLAG(B_SELECT_ERROR))) {
|
||||||
FD_SET(fd, readSet);
|
FD_SET(fd, readSet);
|
||||||
@@ -584,12 +584,16 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout,
|
|||||||
int fd = fds[i].fd;
|
int fd = fds[i].fd;
|
||||||
|
|
||||||
// initialize events masks
|
// initialize events masks
|
||||||
sync->set[i].selected_events = fds[i].events
|
fds[i].events |= POLLNVAL | POLLERR | POLLHUP;
|
||||||
| POLLNVAL | POLLERR | POLLHUP;
|
sync->set[i].selected_events = fds[i].events;
|
||||||
sync->set[i].events = 0;
|
sync->set[i].events = 0;
|
||||||
fds[i].revents = 0;
|
fds[i].revents = 0;
|
||||||
|
|
||||||
if (fd >= 0 && select_fd(fd, sync->set + i, kernel) != B_OK) {
|
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;
|
sync->set[i].events = POLLNVAL;
|
||||||
fds[i].revents = POLLNVAL;
|
fds[i].revents = POLLNVAL;
|
||||||
// indicates that the FD doesn't need to be deselected
|
// 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;
|
continue;
|
||||||
|
|
||||||
// POLLxxx flags and B_SELECT_xxx flags are compatible
|
// POLLxxx flags and B_SELECT_xxx flags are compatible
|
||||||
fds[i].revents = sync->set[i].events
|
fds[i].revents = sync->set[i].events & fds[i].events;
|
||||||
& sync->set[i].selected_events;
|
|
||||||
if (fds[i].revents != 0)
|
if (fds[i].revents != 0)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -676,12 +679,16 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
|
|||||||
int32 object = infos[i].object;
|
int32 object = infos[i].object;
|
||||||
|
|
||||||
// initialize events masks
|
// initialize events masks
|
||||||
sync->set[i].selected_events = infos[i].events
|
infos[i].events |= B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
|
||||||
| B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
|
sync->set[i].selected_events = infos[i].events;
|
||||||
sync->set[i].events = 0;
|
sync->set[i].events = 0;
|
||||||
infos[i].events = 0;
|
infos[i].events = 0;
|
||||||
|
|
||||||
if (select_object(type, object, sync->set + i, kernel) != B_OK) {
|
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;
|
sync->set[i].events = B_EVENT_INVALID;
|
||||||
infos[i].events = B_EVENT_INVALID;
|
infos[i].events = B_EVENT_INVALID;
|
||||||
// indicates that the object doesn't need to be deselected
|
// 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;
|
ssize_t count = 0;
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
for (int i = 0; i < numInfos; i++) {
|
for (int i = 0; i < numInfos; i++) {
|
||||||
infos[i].events = sync->set[i].events
|
infos[i].events &= sync->set[i].events;
|
||||||
& sync->set[i].selected_events;
|
|
||||||
if (infos[i].events != 0)
|
if (infos[i].events != 0)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -562,9 +562,10 @@ select_fd(int32 fd, struct select_info* info, bool kernel)
|
|||||||
// immediately notify the select call
|
// immediately notify the select call
|
||||||
eventsToSelect &= ~SELECT_OUTPUT_ONLY_FLAGS;
|
eventsToSelect &= ~SELECT_OUTPUT_ONLY_FLAGS;
|
||||||
if (eventsToSelect != 0)
|
if (eventsToSelect != 0)
|
||||||
return notify_select_events(info, eventsToSelect);
|
notify_select_events(info, eventsToSelect);
|
||||||
else
|
|
||||||
return B_OK;
|
info->selected_events = 0;
|
||||||
|
return B_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need the FD to stay open while we're doing this, so no select()/
|
// 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 the FS has no select() hook, notify select() now.
|
||||||
if (!HAS_FS_CALL(vnode, select)) {
|
if (!HAS_FS_CALL(vnode, select)) {
|
||||||
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
|
if (!SELECT_TYPE_IS_OUTPUT_ONLY(event))
|
||||||
return notify_select_event(sync, event);
|
notify_select_event(sync, event);
|
||||||
else
|
return B_UNSUPPORTED;
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FS_CALL(vnode, select, descriptor->cookie, event, sync);
|
return FS_CALL(vnode, select, descriptor->cookie, event, sync);
|
||||||
|
|||||||
Reference in New Issue
Block a user