kernel/wait_for_objects: Use BStackOrHeapArray for userland data.

Especially in select(), this cuts overhead significantly,
as we now only invoke malloc() once, and for small select()s
we never have to.
This commit is contained in:
Augustin Cavalier
2022-03-04 16:56:46 -05:00
parent 856721d9fe
commit f666c0873e
+50 -76
View File
@@ -19,6 +19,7 @@
#include <Select.h> #include <Select.h>
#include <AutoDeleter.h> #include <AutoDeleter.h>
#include <StackOrHeapArray.h>
#include <fs/fd.h> #include <fs/fd.h>
#include <port.h> #include <port.h>
@@ -945,9 +946,7 @@ ssize_t
_user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet, _user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet,
fd_set *userErrorSet, bigtime_t timeout, const sigset_t *userSigMask) 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; int result;
if (timeout >= 0) { if (timeout >= 0) {
@@ -968,45 +967,43 @@ _user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet,
// copy parameters // copy parameters
if (userReadSet != NULL) { BStackOrHeapArray<char, 128> sets(bytes * (
readSet = (fd_set *)malloc(bytes); ((userReadSet != NULL) ? 1 : 0) +
if (readSet == NULL) ((userWriteSet != NULL) ? 1 : 0) +
return B_NO_MEMORY; ((userErrorSet != NULL) ? 1 : 0)));
if (!sets.IsValid())
return B_NO_MEMORY;
if (user_memcpy(readSet, userReadSet, bytes) < B_OK) { char *nextSet = &sets[0];
result = B_BAD_ADDRESS; fd_set *readSet = NULL, *writeSet = NULL, *errorSet = NULL;
goto err;
} if (userReadSet != NULL) {
readSet = (fd_set *)nextSet;
nextSet += bytes;
if (user_memcpy(readSet, userReadSet, bytes) != B_OK)
return B_BAD_ADDRESS;
} }
if (userWriteSet != NULL) { if (userWriteSet != NULL) {
writeSet = (fd_set *)malloc(bytes); writeSet = (fd_set *)nextSet;
if (writeSet == NULL) { nextSet += bytes;
result = B_NO_MEMORY;
goto err; if (user_memcpy(writeSet, userWriteSet, bytes) != B_OK)
} return B_BAD_ADDRESS;
if (user_memcpy(writeSet, userWriteSet, bytes) < B_OK) {
result = B_BAD_ADDRESS;
goto err;
}
} }
if (userErrorSet != NULL) { if (userErrorSet != NULL) {
errorSet = (fd_set *)malloc(bytes); errorSet = (fd_set *)nextSet;
if (errorSet == NULL) {
result = B_NO_MEMORY; if (user_memcpy(errorSet, userErrorSet, bytes) != B_OK)
goto err; return B_BAD_ADDRESS;
}
if (user_memcpy(errorSet, userErrorSet, bytes) < B_OK) {
result = B_BAD_ADDRESS;
goto err;
}
} }
sigset_t sigMask;
if (userSigMask != NULL if (userSigMask != NULL
&& user_memcpy(&sigMask, userSigMask, sizeof(sigMask)) < B_OK) { && user_memcpy(&sigMask, userSigMask, sizeof(sigMask)) != B_OK) {
result = B_BAD_ADDRESS; return B_BAD_ADDRESS;
goto err;
} }
result = common_select(numFDs, readSet, writeSet, errorSet, timeout, result = common_select(numFDs, readSet, writeSet, errorSet, timeout,
@@ -1024,11 +1021,6 @@ _user_select(int numFDs, fd_set *userReadSet, fd_set *userWriteSet,
result = B_BAD_ADDRESS; result = B_BAD_ADDRESS;
} }
err:
free(readSet);
free(writeSet);
free(errorSet);
return result; return result;
} }
@@ -1037,11 +1029,6 @@ ssize_t
_user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout, _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout,
const sigset_t *userSigMask) const sigset_t *userSigMask)
{ {
struct pollfd *fds = NULL;
size_t bytes = 0;
sigset_t sigMask;
int result;
if (timeout >= 0) { if (timeout >= 0) {
timeout += system_time(); timeout += system_time();
// deal with overflow // deal with overflow
@@ -1049,35 +1036,30 @@ _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout,
timeout = B_INFINITE_TIMEOUT; timeout = B_INFINITE_TIMEOUT;
} }
if (numFDs < 0) if (numFDs < 0 || !check_max_fds(numFDs))
return B_BAD_VALUE; return B_BAD_VALUE;
BStackOrHeapArray<struct pollfd, 16> fds(numFDs);
if (!fds.IsValid())
return B_NO_MEMORY;
size_t bytes = 0;
if (numFDs != 0) { if (numFDs != 0) {
if (!check_max_fds(numFDs))
return B_BAD_VALUE;
if (userfds == NULL || !IS_USER_ADDRESS(userfds)) if (userfds == NULL || !IS_USER_ADDRESS(userfds))
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
fds = (struct pollfd *)malloc(bytes = numFDs * sizeof(struct pollfd)); if (user_memcpy(fds, userfds, bytes) < B_OK)
if (fds == NULL) return B_BAD_ADDRESS;
return B_NO_MEMORY;
if (user_memcpy(fds, userfds, bytes) < B_OK) {
result = B_BAD_ADDRESS;
goto err;
}
} }
sigset_t sigMask;
if (userSigMask != NULL if (userSigMask != NULL
&& (!IS_USER_ADDRESS(userSigMask) && (!IS_USER_ADDRESS(userSigMask)
|| user_memcpy(&sigMask, userSigMask, sizeof(sigMask)) < B_OK)) { || user_memcpy(&sigMask, userSigMask, sizeof(sigMask)) < B_OK)) {
result = B_BAD_ADDRESS; return B_BAD_ADDRESS;
goto err;
} }
result = common_poll(fds, numFDs, timeout, status_t result = common_poll(fds, numFDs, timeout,
userSigMask != NULL ? &sigMask : NULL, false); userSigMask != NULL ? &sigMask : NULL, false);
// copy back results // copy back results
@@ -1085,8 +1067,6 @@ _user_poll(struct pollfd *userfds, int numFDs, bigtime_t timeout,
if (result >= 0) if (result >= 0)
result = B_BAD_ADDRESS; result = B_BAD_ADDRESS;
} }
err:
free(fds);
return result; return result;
} }
@@ -1114,27 +1094,21 @@ _user_wait_for_objects(object_wait_info* userInfos, int numInfos, uint32 flags,
if (userInfos == NULL || !IS_USER_ADDRESS(userInfos)) if (userInfos == NULL || !IS_USER_ADDRESS(userInfos))
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
int bytes = sizeof(object_wait_info) * numInfos; BStackOrHeapArray<object_wait_info, 16> infos(numInfos);
object_wait_info* infos = (object_wait_info*)malloc(bytes); if (!infos.IsValid())
if (infos == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
const int bytes = sizeof(object_wait_info) * numInfos;
// copy parameters to kernel space, call the function, and copy the results if (user_memcpy(infos, userInfos, bytes) != B_OK)
// back return B_BAD_ADDRESS;
ssize_t result;
if (user_memcpy(infos, userInfos, bytes) == B_OK) {
result = common_wait_for_objects(infos, numInfos, flags, timeout,
false);
if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK) { ssize_t result = common_wait_for_objects(infos, numInfos, flags, timeout, false);
result = B_BAD_ADDRESS;
} else if (result >= 0 && user_memcpy(userInfos, infos, bytes) != B_OK) {
syscall_restart_handle_timeout_post(result, timeout);
} else
result = B_BAD_ADDRESS; result = B_BAD_ADDRESS;
} else {
free(infos); syscall_restart_handle_timeout_post(result, timeout);
}
return result; return result;
} }