Kernel: Factor out common code from read/readv syscalls

Having these bits of code factored out not only prevents duplication
now, but will also allow us to implement pread without repeating
ourselves (too much).
This commit is contained in:
Rodrigo Tobar 2021-10-12 20:59:49 +08:00 committed by Andreas Kling
parent 52976bfac6
commit 8936b111a7
Notes: sideshowbarker 2024-07-18 02:47:26 +09:00

View file

@ -12,6 +12,31 @@ namespace Kernel {
using BlockFlags = Thread::FileBlocker::BlockFlags; using BlockFlags = Thread::FileBlocker::BlockFlags;
static KResultOr<OpenFileDescription*> open_readable_file_description(Process::OpenFileDescriptions const& fds, int fd)
{
auto description = TRY(fds.open_file_description(fd));
if (!description->is_readable())
return EBADF;
if (description->is_directory())
return EISDIR;
return description;
}
static KResult check_blocked_read(OpenFileDescription* description)
{
if (description->is_blocking()) {
if (!description->can_read()) {
auto unblock_flags = BlockFlags::None;
if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
return EINTR;
if (!has_flag(unblock_flags, BlockFlags::Read))
return EAGAIN;
// TODO: handle exceptions in unblock_flags
}
}
return KSuccess;
}
KResultOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count) KResultOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov, int iov_count)
{ {
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this) VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this)
@ -34,24 +59,11 @@ KResultOr<FlatPtr> Process::sys$readv(int fd, Userspace<const struct iovec*> iov
return EINVAL; return EINVAL;
} }
auto description = TRY(fds().open_file_description(fd)); auto description = TRY(open_readable_file_description(fds(), fd));
if (!description->is_readable())
return EBADF;
if (description->is_directory())
return EISDIR;
int nread = 0; int nread = 0;
for (auto& vec : vecs) { for (auto& vec : vecs) {
if (description->is_blocking()) { TRY(check_blocked_read(description));
if (!description->can_read()) {
auto unblock_flags = BlockFlags::None;
if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
return EINTR;
if (!has_flag(unblock_flags, BlockFlags::Read))
return EAGAIN;
// TODO: handle exceptions in unblock_flags
}
}
auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len); auto buffer = UserOrKernelBuffer::for_user_buffer((u8*)vec.iov_base, vec.iov_len);
if (!buffer.has_value()) if (!buffer.has_value())
return EFAULT; return EFAULT;
@ -71,21 +83,8 @@ KResultOr<FlatPtr> Process::sys$read(int fd, Userspace<u8*> buffer, size_t size)
if (size > NumericLimits<ssize_t>::max()) if (size > NumericLimits<ssize_t>::max())
return EINVAL; return EINVAL;
dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size); dbgln_if(IO_DEBUG, "sys$read({}, {}, {})", fd, buffer.ptr(), size);
auto description = TRY(fds().open_file_description(fd)); auto description = TRY(open_readable_file_description(fds(), fd));
if (!description->is_readable()) TRY(check_blocked_read(description));
return EBADF;
if (description->is_directory())
return EISDIR;
if (description->is_blocking()) {
if (!description->can_read()) {
auto unblock_flags = BlockFlags::None;
if (Thread::current()->block<Thread::ReadBlocker>({}, *description, unblock_flags).was_interrupted())
return EINTR;
if (!has_flag(unblock_flags, BlockFlags::Read))
return EAGAIN;
// TODO: handle exceptions in unblock_flags
}
}
auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size); auto user_buffer = UserOrKernelBuffer::for_user_buffer(buffer, size);
if (!user_buffer.has_value()) if (!user_buffer.has_value())
return EFAULT; return EFAULT;