common_poll():

* Always select POLLNVAL. We wouldn't get notified, if the FD was closed while
  waiting.
* Skip negative FDs (as per POSIX standard).
* When encountering an invalid FD, we must not wait. Previously we did that as
  long as any FD was valid.
* The return count must consider all FDs with non-null revents, including
  invalid ones (revents is POLLNVAL then).

common_poll()/common_wait_for_objects():
* Don't bail out early, when no FDs/objects have been selected. We always want
  to wait.

_user_poll()/_user_wait_for_objects():
* Copy the array back to userland even if common_*() returned an error. The
  functions do now always fill in the resulting events.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32418 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-08-15 16:42:18 +00:00
parent 57dc0e2a53
commit 4e4ff20294

View File

@ -1,5 +1,5 @@
/*
* Copyright 2007-2008, Ingo Weinhold, bonefish@cs.tu-berlin.de.
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
@ -495,7 +495,7 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
PRINT(("common_select(): events deselected\n"));
// collect the events that happened in the meantime
// collect the events that have happened in the meantime
int count = 0;
@ -546,13 +546,9 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
static int
common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
{
status_t status = B_OK;
int count = 0;
uint32 i;
// allocate sync object
select_sync* sync;
status = create_select_sync(numFDs, sync);
status_t status = create_select_sync(numFDs, sync);
if (status != B_OK)
return status;
@ -560,41 +556,43 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
// start polling file descriptors (by selecting them)
for (i = 0; i < numFDs; i++) {
bool invalid = false;
for (uint32 i = 0; i < numFDs; i++) {
int fd = fds[i].fd;
// initialize events masks
sync->set[i].selected_events = (fds[i].events & ~POLLNVAL)
| POLLERR | POLLHUP;
sync->set[i].selected_events = fds[i].events
| POLLNVAL | POLLERR | POLLHUP;
sync->set[i].events = 0;
fds[i].revents = 0;
if (select_fd(fd, sync->set + i, kernel) == B_OK) {
fds[i].revents = 0;
if (sync->set[i].selected_events != 0)
count++;
} else
if (fd >= 0 && select_fd(fd, sync->set + i, kernel) != B_OK) {
sync->set[i].events = POLLNVAL;
fds[i].revents = POLLNVAL;
// indicates that the FD doesn't need to be deselected
invalid = true;
}
}
if (numFDs > 0 && count < 1) {
count = B_BAD_VALUE;
goto err;
if (!invalid) {
status = acquire_sem_etc(sync->sem, 1,
B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout);
}
status = acquire_sem_etc(sync->sem, 1,
B_CAN_INTERRUPT | (timeout >= 0 ? B_ABSOLUTE_TIMEOUT : 0), timeout);
// deselect file descriptors
for (i = 0; i < numFDs; i++)
deselect_fd(fds[i].fd, sync->set + i, kernel);
for (uint32 i = 0; i < numFDs; i++) {
if (fds[i].fd >= 0 && (fds[i].revents & POLLNVAL) == 0)
deselect_fd(fds[i].fd, sync->set + i, kernel);
}
// collect the events that are happened in the meantime
// collect the events that have happened in the meantime
int count = 0;
switch (status) {
case B_OK:
for (count = 0, i = 0; i < numFDs; i++) {
if (fds[i].revents == POLLNVAL)
for (uint32 i = 0; i < numFDs; i++) {
if (fds[i].fd < 0)
continue;
// POLLxxx flags and B_SELECT_xxx flags are compatible
@ -609,10 +607,9 @@ common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
break;
default:
// B_TIMED_OUT, and B_WOULD_BLOCK
count = 0;
break;
}
err:
put_select_sync(sync);
T(PollDone(fds, numFDs, count));
@ -635,7 +632,6 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
// start selecting objects
ssize_t count = 0;
bool invalid = false;
for (int i = 0; i < numInfos; i++) {
uint16 type = infos[i].type;
@ -645,24 +641,17 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
sync->set[i].selected_events = infos[i].events
| B_EVENT_INVALID | B_EVENT_ERROR | B_EVENT_DISCONNECTED;
sync->set[i].events = 0;
infos[i].events = 0;
if (type < kSelectOpsCount
&& kSelectOps[type].select(object, sync->set + i, kernel) == B_OK) {
infos[i].events = 0;
if (sync->set[i].selected_events != 0)
count++;
} else {
sync->set[i].selected_events = B_EVENT_INVALID;
if (type >= kSelectOpsCount
|| kSelectOps[type].select(object, sync->set + i, kernel) != B_OK) {
sync->set[i].events = B_EVENT_INVALID;
infos[i].events = B_EVENT_INVALID;
// indicates that the object doesn't need to be deselected
invalid = true;
}
}
if (numInfos > 0 && count < 1) {
put_select_sync(sync);
return B_BAD_VALUE;
}
if (!invalid) {
status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | flags,
timeout);
@ -677,22 +666,19 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
kSelectOps[type].deselect(infos[i].object, sync->set + i, kernel);
}
// collect the events that are happened in the meantime
// collect the events that have happened in the meantime
switch (status) {
case B_OK:
count = 0;
for (int i = 0; i < numInfos; i++) {
infos[i].events = sync->set[i].events
& sync->set[i].selected_events;
if (infos[i].events != 0)
count++;
}
break;
default:
// B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK
count = status;
break;
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;
if (infos[i].events != 0)
count++;
}
} else {
// B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK
count = status;
}
put_select_sync(sync);
@ -1040,9 +1026,10 @@ _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout)
result = common_poll(fds, numFDs, timeout, false);
// copy back results
if (result >= 0 && numFDs > 0 && user_memcpy(userfds, fds, bytes) < B_OK)
result = B_BAD_ADDRESS;
else
if (numFDs > 0 && user_memcpy(userfds, fds, bytes) != 0) {
if (result >= 0)
result = B_BAD_ADDRESS;
} else
syscall_restart_handle_timeout_post(result, timeout);
err:
@ -1084,9 +1071,10 @@ _user_wait_for_objects(object_wait_info* userInfos, int numInfos, uint32 flags,
result = common_wait_for_objects(infos, numInfos, flags, timeout,
false);
if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK)
result = B_BAD_ADDRESS;
else
if (user_memcpy(userInfos, infos, bytes) != B_OK) {
if (result >= 0)
result = B_BAD_ADDRESS;
} else
syscall_restart_handle_timeout_post(result, timeout);
} else
result = B_BAD_ADDRESS;