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:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007-2008, Ingo Weinhold, [email protected].de.
|
* Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2002-2008, Axel Dörfler, [email protected].
|
* Copyright 2002-2008, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* 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"));
|
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;
|
int count = 0;
|
||||||
|
|
||||||
@@ -546,13 +546,9 @@ common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
|
|||||||
static int
|
static int
|
||||||
common_poll(struct pollfd *fds, nfds_t numFDs, bigtime_t timeout, bool kernel)
|
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
|
// allocate sync object
|
||||||
select_sync* sync;
|
select_sync* sync;
|
||||||
status = create_select_sync(numFDs, sync);
|
status_t status = create_select_sync(numFDs, sync);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
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)
|
// 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;
|
int fd = fds[i].fd;
|
||||||
|
|
||||||
// initialize events masks
|
// initialize events masks
|
||||||
sync->set[i].selected_events = (fds[i].events & ~POLLNVAL)
|
sync->set[i].selected_events = fds[i].events
|
||||||
| POLLERR | POLLHUP;
|
| POLLNVAL | POLLERR | POLLHUP;
|
||||||
sync->set[i].events = 0;
|
sync->set[i].events = 0;
|
||||||
|
fds[i].revents = 0;
|
||||||
|
|
||||||
if (select_fd(fd, sync->set + i, kernel) == B_OK) {
|
if (fd >= 0 && select_fd(fd, sync->set + i, kernel) != B_OK) {
|
||||||
fds[i].revents = 0;
|
sync->set[i].events = POLLNVAL;
|
||||||
if (sync->set[i].selected_events != 0)
|
|
||||||
count++;
|
|
||||||
} else
|
|
||||||
fds[i].revents = POLLNVAL;
|
fds[i].revents = POLLNVAL;
|
||||||
|
// indicates that the FD doesn't need to be deselected
|
||||||
|
invalid = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numFDs > 0 && count < 1) {
|
if (!invalid) {
|
||||||
count = B_BAD_VALUE;
|
status = acquire_sem_etc(sync->sem, 1,
|
||||||
goto err;
|
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
|
// deselect file descriptors
|
||||||
|
|
||||||
for (i = 0; i < numFDs; i++)
|
for (uint32 i = 0; i < numFDs; i++) {
|
||||||
deselect_fd(fds[i].fd, sync->set + i, kernel);
|
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) {
|
switch (status) {
|
||||||
case B_OK:
|
case B_OK:
|
||||||
for (count = 0, i = 0; i < numFDs; i++) {
|
for (uint32 i = 0; i < numFDs; i++) {
|
||||||
if (fds[i].revents == POLLNVAL)
|
if (fds[i].fd < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// POLLxxx flags and B_SELECT_xxx flags are compatible
|
// 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;
|
break;
|
||||||
default:
|
default:
|
||||||
// B_TIMED_OUT, and B_WOULD_BLOCK
|
// B_TIMED_OUT, and B_WOULD_BLOCK
|
||||||
count = 0;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
|
||||||
put_select_sync(sync);
|
put_select_sync(sync);
|
||||||
|
|
||||||
T(PollDone(fds, numFDs, count));
|
T(PollDone(fds, numFDs, count));
|
||||||
@@ -635,7 +632,6 @@ common_wait_for_objects(object_wait_info* infos, int numInfos, uint32 flags,
|
|||||||
|
|
||||||
// start selecting objects
|
// start selecting objects
|
||||||
|
|
||||||
ssize_t count = 0;
|
|
||||||
bool invalid = false;
|
bool invalid = false;
|
||||||
for (int i = 0; i < numInfos; i++) {
|
for (int i = 0; i < numInfos; i++) {
|
||||||
uint16 type = infos[i].type;
|
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
|
sync->set[i].selected_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].events = 0;
|
sync->set[i].events = 0;
|
||||||
|
infos[i].events = 0;
|
||||||
|
|
||||||
if (type < kSelectOpsCount
|
if (type >= kSelectOpsCount
|
||||||
&& kSelectOps[type].select(object, sync->set + i, kernel) == B_OK) {
|
|| kSelectOps[type].select(object, sync->set + i, kernel) != B_OK) {
|
||||||
infos[i].events = 0;
|
sync->set[i].events = B_EVENT_INVALID;
|
||||||
if (sync->set[i].selected_events != 0)
|
|
||||||
count++;
|
|
||||||
} else {
|
|
||||||
sync->set[i].selected_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
|
||||||
invalid = true;
|
invalid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numInfos > 0 && count < 1) {
|
|
||||||
put_select_sync(sync);
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!invalid) {
|
if (!invalid) {
|
||||||
status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | flags,
|
status = acquire_sem_etc(sync->sem, 1, B_CAN_INTERRUPT | flags,
|
||||||
timeout);
|
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);
|
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) {
|
ssize_t count = 0;
|
||||||
case B_OK:
|
if (status == B_OK) {
|
||||||
count = 0;
|
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;
|
||||||
& sync->set[i].selected_events;
|
if (infos[i].events != 0)
|
||||||
if (infos[i].events != 0)
|
count++;
|
||||||
count++;
|
}
|
||||||
}
|
} else {
|
||||||
break;
|
// B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK
|
||||||
default:
|
count = status;
|
||||||
// B_INTERRUPTED, B_TIMED_OUT, and B_WOULD_BLOCK
|
|
||||||
count = status;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put_select_sync(sync);
|
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);
|
result = common_poll(fds, numFDs, timeout, false);
|
||||||
|
|
||||||
// copy back results
|
// copy back results
|
||||||
if (result >= 0 && numFDs > 0 && user_memcpy(userfds, fds, bytes) < B_OK)
|
if (numFDs > 0 && user_memcpy(userfds, fds, bytes) != 0) {
|
||||||
result = B_BAD_ADDRESS;
|
if (result >= 0)
|
||||||
else
|
result = B_BAD_ADDRESS;
|
||||||
|
} else
|
||||||
syscall_restart_handle_timeout_post(result, timeout);
|
syscall_restart_handle_timeout_post(result, timeout);
|
||||||
|
|
||||||
err:
|
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,
|
result = common_wait_for_objects(infos, numInfos, flags, timeout,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK)
|
if (user_memcpy(userInfos, infos, bytes) != B_OK) {
|
||||||
result = B_BAD_ADDRESS;
|
if (result >= 0)
|
||||||
else
|
result = B_BAD_ADDRESS;
|
||||||
|
} else
|
||||||
syscall_restart_handle_timeout_post(result, timeout);
|
syscall_restart_handle_timeout_post(result, timeout);
|
||||||
} else
|
} else
|
||||||
result = B_BAD_ADDRESS;
|
result = B_BAD_ADDRESS;
|
||||||
|
|||||||
Reference in New Issue
Block a user