Serenity Operating System
at master 139 lines 5.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ScopeGuard.h> 8#include <AK/Time.h> 9#include <Kernel/API/POSIX/select.h> 10#include <Kernel/Debug.h> 11#include <Kernel/FileSystem/OpenFileDescription.h> 12#include <Kernel/Process.h> 13 14namespace Kernel { 15 16using BlockFlags = Thread::FileBlocker::BlockFlags; 17 18ErrorOr<FlatPtr> Process::sys$poll(Userspace<Syscall::SC_poll_params const*> user_params) 19{ 20 VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); 21 TRY(require_promise(Pledge::stdio)); 22 23 auto params = TRY(copy_typed_from_user(user_params)); 24 25 if (params.nfds >= OpenFileDescriptions::max_open()) 26 return ENOBUFS; 27 28 Thread::BlockTimeout timeout; 29 if (params.timeout) { 30 auto timeout_time = TRY(copy_time_from_user(params.timeout)); 31 timeout = Thread::BlockTimeout(false, &timeout_time); 32 } 33 34 sigset_t sigmask = {}; 35 if (params.sigmask) 36 TRY(copy_from_user(&sigmask, params.sigmask)); 37 38 Vector<pollfd, FD_SETSIZE> fds_copy; 39 if (params.nfds > 0) { 40 Checked<size_t> nfds_checked = sizeof(pollfd); 41 nfds_checked *= params.nfds; 42 if (nfds_checked.has_overflow()) 43 return EFAULT; 44 TRY(fds_copy.try_resize(params.nfds)); 45 TRY(copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value())); 46 } 47 48 Thread::SelectBlocker::FDVector fds_info; 49 TRY(fds_info.try_ensure_capacity(params.nfds)); 50 51 TRY(m_fds.with_shared([&](auto& fds) -> ErrorOr<void> { 52 for (size_t i = 0; i < params.nfds; i++) { 53 auto& pfd = fds_copy[i]; 54 RefPtr<OpenFileDescription> description; 55 auto description_or_error = fds.open_file_description(pfd.fd); 56 if (!description_or_error.is_error()) 57 description = description_or_error.release_value(); 58 BlockFlags block_flags = BlockFlags::WriteError | BlockFlags::WriteHangUp; // always want POLLERR, POLLHUP, POLLNVAL 59 if (pfd.events & POLLIN) 60 block_flags |= BlockFlags::Read; 61 if (pfd.events & POLLOUT) 62 block_flags |= BlockFlags::Write; 63 if (pfd.events & POLLPRI) 64 block_flags |= BlockFlags::ReadPriority; 65 if (pfd.events & POLLWRBAND) 66 block_flags |= BlockFlags::WritePriority; 67 if (pfd.events & POLLRDHUP) 68 block_flags |= BlockFlags::ReadHangUp; 69 fds_info.unchecked_append({ move(description), block_flags }); 70 } 71 return {}; 72 })); 73 74 auto* current_thread = Thread::current(); 75 76 u32 previous_signal_mask = 0; 77 if (params.sigmask) 78 previous_signal_mask = current_thread->update_signal_mask(sigmask); 79 ScopeGuard rollback_signal_mask([&]() { 80 if (params.sigmask) 81 current_thread->update_signal_mask(previous_signal_mask); 82 }); 83 84 if constexpr (IO_DEBUG || POLL_SELECT_DEBUG) 85 dbgln("polling on {} fds, timeout={}", fds_info.size(), params.timeout); 86 87 if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) 88 return EINTR; 89 90 int fds_with_revents = 0; 91 92 for (unsigned i = 0; i < params.nfds; ++i) { 93 auto& pfd = fds_copy[i]; 94 auto& fds_entry = fds_info[i]; 95 96 pfd.revents = 0; 97 if (fds_entry.unblocked_flags == BlockFlags::None) 98 continue; 99 100 if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteHangUp)) 101 pfd.revents |= POLLHUP; 102 if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteError) || !fds_entry.description) { 103 if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteError)) 104 pfd.revents |= POLLERR; 105 if (!fds_entry.description) 106 pfd.revents |= POLLNVAL; 107 } else { 108 if (has_flag(fds_entry.unblocked_flags, BlockFlags::Read)) { 109 VERIFY(pfd.events & POLLIN); 110 pfd.revents |= POLLIN; 111 } 112 if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadPriority)) { 113 VERIFY(pfd.events & POLLPRI); 114 pfd.revents |= POLLPRI; 115 } 116 if (!has_flag(fds_entry.unblocked_flags, BlockFlags::WriteHangUp) && has_flag(fds_entry.unblocked_flags, BlockFlags::Write)) { 117 VERIFY(pfd.events & POLLOUT); 118 pfd.revents |= POLLOUT; 119 } 120 if (has_flag(fds_entry.unblocked_flags, BlockFlags::WritePriority)) { 121 VERIFY(pfd.events & POLLWRBAND); 122 pfd.revents |= POLLWRBAND; 123 } 124 if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadHangUp)) { 125 VERIFY(pfd.events & POLLRDHUP); 126 pfd.revents |= POLLRDHUP; 127 } 128 } 129 if (pfd.revents) 130 fds_with_revents++; 131 } 132 133 if (params.nfds > 0) 134 TRY(copy_to_user(&params.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd))); 135 136 return fds_with_revents; 137} 138 139}