* common_select() now also clears the sets for B_WOULD_BLOCK and any other error

that returns 0. Patch by Hugo Santos.
* Removed superfluous memset() of select_sync structures.
* Some cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20467 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-03-29 16:09:53 +00:00
parent 340e1a9702
commit 6da6433598
2 changed files with 102 additions and 104 deletions

View File

@ -1,20 +1,21 @@
/*
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "vfs_select.h"
#include <vfs.h>
#include <fd.h>
#include <syscalls.h>
#include <fs/select_sync_pool.h>
#include "vfs_select.h"
#include <sys/select.h>
#include <new>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
//#define TRACE_VFS_SELECT
#ifdef TRACE_VFS_SELECT
@ -26,10 +27,10 @@
#endif
/** Selects all events in the mask on the specified file descriptor */
/*! Selects all events in the mask on the specified file descriptor */
static int
select_events(struct select_sync *sync, int fd, int ref, uint16 selectedEvents, bool kernel)
select_events(struct select_sync *sync, int fd, int ref, uint16 selectedEvents,
bool kernel)
{
uint32 count = 0;
uint16 event = 1;
@ -44,10 +45,10 @@ select_events(struct select_sync *sync, int fd, int ref, uint16 selectedEvents,
}
/** Deselects all events in the mask on the specified file descriptor */
/*! Deselects all events in the mask on the specified file descriptor */
static void
deselect_events(struct select_sync *sync, int fd, uint16 selectedEvents, bool kernel)
deselect_events(struct select_sync *sync, int fd, uint16 selectedEvents,
bool kernel)
{
uint16 event = 1;
@ -59,37 +60,36 @@ deselect_events(struct select_sync *sync, int fd, uint16 selectedEvents, bool ke
}
/** Clears all bits in the fd_set - since we are using variable sized
* arrays in the kernel, we can't use the FD_ZERO() macro provided by
* sys/select.h for this task.
* All other FD_xxx() macros are safe to use, though.
*/
/*!
Clears all bits in the fd_set - since we are using variable sized
arrays in the kernel, we can't use the FD_ZERO() macro provided by
sys/select.h for this task.
All other FD_xxx() macros are safe to use, though.
*/
static inline void
fd_zero(fd_set *set, int numfds)
fd_zero(fd_set *set, int numFDs)
{
if (set != NULL)
memset(set, 0, _howmany(numfds, NFDBITS) * sizeof(fd_mask));
memset(set, 0, _howmany(numFDs, NFDBITS) * sizeof(fd_mask));
}
static int
common_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
common_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
bigtime_t timeout, const sigset_t *sigMask, bool kernel)
{
struct select_sync sync;
status_t status = B_OK;
int count = 0;
int fd;
FUNCTION(("common_select(%d, %p, %p, %p, %lld, %p, %d)\n", numfds, readSet,
FUNCTION(("common_select(%d, %p, %p, %p, %lld, %p, %d)\n", numFDs, readSet,
writeSet, errorSet, timeout, sigMask, kernel));
// ToDo: set sigMask to make pselect() functional different from select()
// TODO: set sigMask to make pselect() functional different from select()
// check if fds are valid before doing anything
for (fd = 0; fd < numfds; fd++) {
for (fd = 0; fd < numFDs; fd++) {
if (((readSet && FD_ISSET(fd, readSet))
|| (writeSet && FD_ISSET(fd, writeSet))
|| (errorSet && FD_ISSET(fd, errorSet)))
@ -99,24 +99,22 @@ common_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
// allocate resources
memset(&sync, 0, sizeof(select_sync));
sync.sem = create_sem(0, "select");
if (sync.sem < B_OK)
return sync.sem;
set_sem_owner(sync.sem, B_SYSTEM_TEAM);
sync.set = (select_info*)malloc(sizeof(select_info) * numfds);
sync.set = (select_info *)malloc(sizeof(select_info) * numFDs);
if (sync.set == NULL) {
delete_sem(sync.sem);
return B_NO_MEMORY;
}
sync.count = numfds;
sync.count = numFDs;
// start selecting file descriptors
for (fd = 0; fd < numfds; fd++) {
for (fd = 0; fd < numFDs; fd++) {
sync.set[fd].selected_events = 0;
sync.set[fd].events = 0;
@ -127,7 +125,7 @@ common_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
if (errorSet && FD_ISSET(fd, errorSet))
sync.set[fd].selected_events |= SELECT_FLAG(B_SELECT_ERROR);
count += select_events(&sync, fd, fd, sync.set[fd].selected_events, kernel);
select_events(&sync, fd, fd, sync.set[fd].selected_events, kernel);
// array position is the same as the fd for select()
}
@ -138,9 +136,9 @@ common_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
// deselect file descriptors
for (fd = 0; fd < numfds; fd++)
for (fd = 0; fd < numFDs; fd++) {
deselect_events(&sync, fd, sync.set[fd].selected_events, kernel);
// ToDo: Since we're using FD indices instead of FDs (file_descriptors),
// TODO: Since we're using FD indices instead of FDs (file_descriptors),
// it can happen that the FD index (even the FD) on which we invoked
// the select() FS hook is already closed at this point.
// This has two main consequences:
@ -154,50 +152,47 @@ common_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
// second call to notify_select_event() might be too late, since
// select() might already be finished. Dangerous!
// notify_select_event() would operate on already free()d memory!
}
PRINT(("common_select(): events deselected\n"));
// collect the events that are happened in the meantime
// collect the events that happened in the meantime
switch (status) {
case B_OK:
// Clear sets to store the received events
// (we don't use the macros, because we have variable sized arrays;
// the other FD_xxx() macros are safe, though).
fd_zero(readSet, numfds);
fd_zero(writeSet, numfds);
fd_zero(errorSet, numfds);
int count = 0;
for (count = 0, fd = 0;fd < numfds; fd++) {
if (readSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_READ)) {
FD_SET(fd, readSet);
count++;
}
if (writeSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_WRITE)) {
FD_SET(fd, writeSet);
count++;
}
if (errorSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_ERROR)) {
FD_SET(fd, errorSet);
count++;
}
}
break;
case B_INTERRUPTED:
count = B_INTERRUPTED;
break;
case B_TIMED_OUT:
fd_zero(readSet, numfds);
fd_zero(writeSet, numfds);
fd_zero(errorSet, numfds);
// supposed to fall through
default:
// B_TIMED_OUT, and B_WOULD_BLOCK
count = 0;
if (status == B_INTERRUPTED) {
// We must not clear the sets in this case, as applications may
// rely on the contents of them.
count = B_INTERRUPTED;
goto err;
}
// Clear sets to store the received events
// (we can't use the macros, because we have variable sized arrays;
// the other FD_xxx() macros are safe, though).
fd_zero(readSet, numFDs);
fd_zero(writeSet, numFDs);
fd_zero(errorSet, numFDs);
if (status == B_OK) {
for (count = 0, fd = 0;fd < numFDs; fd++) {
if (readSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_READ)) {
FD_SET(fd, readSet);
count++;
}
if (writeSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_WRITE)) {
FD_SET(fd, writeSet);
count++;
}
if (errorSet && sync.set[fd].events & SELECT_FLAG(B_SELECT_ERROR)) {
FD_SET(fd, errorSet);
count++;
}
}
}
// B_TIMED_OUT and B_WOULD_BLOCK are supposed to return 0
err:
delete_sem(sync.sem);
free(sync.set);
@ -207,7 +202,7 @@ err:
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;
@ -216,24 +211,22 @@ common_poll(struct pollfd *fds, nfds_t numfds, bigtime_t timeout, bool kernel)
// allocate resources
select_sync sync;
memset(&sync, 0, sizeof(select_sync));
sync.sem = create_sem(0, "poll");
if (sync.sem < B_OK)
return sync.sem;
set_sem_owner(sync.sem, B_SYSTEM_TEAM);
sync.set = (select_info*)malloc(numfds * sizeof(select_info));
sync.set = (select_info*)malloc(numFDs * sizeof(select_info));
if (sync.set == NULL) {
delete_sem(sync.sem);
return B_NO_MEMORY;
}
sync.count = numfds;
sync.count = numFDs;
// start polling file descriptors (by selecting them)
for (i = 0; i < numfds; i++) {
for (i = 0; i < numFDs; i++) {
int fd = fds[i].fd;
// check if fds are valid
@ -261,14 +254,16 @@ common_poll(struct pollfd *fds, nfds_t numfds, bigtime_t timeout, bool kernel)
// deselect file descriptors
for (i = 0; i < numfds; i++)
for (i = 0; i < numFDs; i++) {
deselect_events(&sync, fds[i].fd, sync.set[i].selected_events, kernel);
// TODO: same comments apply as on common_select()
}
// collect the events that are happened in the meantime
switch (status) {
case B_OK:
for (count = 0, i = 0; i < numfds; i++) {
for (count = 0, i = 0; i < numFDs; i++) {
if (fds[i].revents == POLLNVAL)
continue;
@ -294,8 +289,7 @@ err:
}
// #pragma mark -
// public functions exported to the kernel
// #pragma mark - public kernel API
status_t
@ -321,8 +315,7 @@ notify_select_event(struct selectsync *_sync, uint32 ref, uint8 event)
}
// #pragma mark -
// currently private select sync pool functions exported to the kernel
// #pragma mark - private kernel exported API
static select_sync_pool_entry *
@ -462,39 +455,38 @@ notify_select_event_pool(select_sync_pool *pool, uint8 event)
}
// #pragma mark -
// Functions called from the POSIX layer
// #pragma mark - Kernel POSIX layer
ssize_t
_kern_select(int numfds, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
_kern_select(int numFDs, fd_set *readSet, fd_set *writeSet, fd_set *errorSet,
bigtime_t timeout, const sigset_t *sigMask)
{
return common_select(numfds, readSet, writeSet, errorSet, timeout, sigMask, true);
return common_select(numFDs, readSet, writeSet, errorSet, timeout,
sigMask, true);
}
ssize_t
_kern_poll(struct pollfd *fds, int numfds, bigtime_t timeout)
_kern_poll(struct pollfd *fds, int numFDs, bigtime_t timeout)
{
return common_poll(fds, numfds, timeout, true);
return common_poll(fds, numFDs, timeout, true);
}
// #pragma mark -
// User syscalls
// #pragma mark - User syscalls
ssize_t
_user_select(int numfds, fd_set *userReadSet, fd_set *userWriteSet, fd_set *userErrorSet,
bigtime_t timeout, const sigset_t *userSigMask)
_user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet,
fd_set *userErrorSet, bigtime_t timeout, const sigset_t *userSigMask)
{
fd_set *readSet = NULL, *writeSet = NULL, *errorSet = NULL;
uint32 bytes = _howmany(numfds, NFDBITS) * sizeof(fd_mask);
uint32 bytes = _howmany(numFDs, NFDBITS) * sizeof(fd_mask);
sigset_t sigMask;
int result;
if (numfds < 0)
if (numFDs < 0)
return B_BAD_VALUE;
if ((userReadSet != NULL && !IS_USER_ADDRESS(userReadSet))
@ -543,14 +535,18 @@ _user_select(int numfds, fd_set *userReadSet, fd_set *userWriteSet, fd_set *user
if (userSigMask != NULL)
sigMask = *userSigMask;
result = common_select(numfds, readSet, writeSet, errorSet, timeout, userSigMask ? &sigMask : NULL, false);
result = common_select(numFDs, readSet, writeSet, errorSet, timeout,
userSigMask ? &sigMask : NULL, false);
// copy back results
if (result >= B_OK
&& ((readSet != NULL && user_memcpy(userReadSet, readSet, bytes) < B_OK)
|| (writeSet != NULL && user_memcpy(userWriteSet, writeSet, bytes) < B_OK)
|| (errorSet != NULL && user_memcpy(userErrorSet, errorSet, bytes) < B_OK)))
&& ((readSet != NULL
&& user_memcpy(userReadSet, readSet, bytes) < B_OK)
|| (writeSet != NULL
&& user_memcpy(userWriteSet, writeSet, bytes) < B_OK)
|| (errorSet != NULL
&& user_memcpy(userErrorSet, errorSet, bytes) < B_OK)))
result = B_BAD_ADDRESS;
err:
@ -563,13 +559,13 @@ err:
ssize_t
_user_poll(struct pollfd *userfds, int numfds, bigtime_t timeout)
_user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout)
{
struct pollfd *fds;
size_t bytes;
int result;
if (numfds < 0)
if (numFDs < 0)
return B_BAD_VALUE;
if (userfds == NULL || !IS_USER_ADDRESS(userfds))
@ -577,7 +573,7 @@ _user_poll(struct pollfd *userfds, int numfds, bigtime_t timeout)
// copy parameters
fds = (struct pollfd *)malloc(bytes = numfds * sizeof(struct pollfd));
fds = (struct pollfd *)malloc(bytes = numFDs * sizeof(struct pollfd));
if (fds == NULL)
return B_NO_MEMORY;
@ -586,7 +582,7 @@ _user_poll(struct pollfd *userfds, int numfds, bigtime_t timeout)
goto err;
}
result = common_poll(fds, numfds, timeout, false);
result = common_poll(fds, numFDs, timeout, false);
// copy back results
if (result >= B_OK && user_memcpy(userfds, fds, bytes) < B_OK)
@ -598,4 +594,3 @@ err:
return result;
}

View File

@ -1,13 +1,16 @@
/*
** Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the Haiku License.
*/
/*
* Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef VFS_SELECT_H
#define VFS_SELECT_H
#include <Select.h>
#include <util/DoublyLinkedList.h>
#include <OS.h>
typedef struct select_info {
uint16 selected_events;