select.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/ScopeGuard.h>
  7. #include <AK/Time.h>
  8. #include <Kernel/Debug.h>
  9. #include <Kernel/FileSystem/FileDescription.h>
  10. #include <Kernel/Process.h>
  11. namespace Kernel {
  12. using BlockFlags = Thread::FileBlocker::BlockFlags;
  13. KResultOr<int> Process::sys$select(Userspace<const Syscall::SC_select_params*> user_params)
  14. {
  15. REQUIRE_PROMISE(stdio);
  16. Syscall::SC_select_params params {};
  17. if (!copy_from_user(&params, user_params))
  18. return EFAULT;
  19. if (params.nfds < 0)
  20. return EINVAL;
  21. Thread::BlockTimeout timeout;
  22. if (params.timeout) {
  23. Optional<Time> timeout_time = copy_time_from_user(params.timeout);
  24. if (!timeout_time.has_value())
  25. return EFAULT;
  26. timeout = Thread::BlockTimeout(false, &timeout_time.value());
  27. }
  28. auto current_thread = Thread::current();
  29. u32 previous_signal_mask = 0;
  30. if (params.sigmask) {
  31. sigset_t sigmask_copy;
  32. if (!copy_from_user(&sigmask_copy, params.sigmask))
  33. return EFAULT;
  34. previous_signal_mask = current_thread->update_signal_mask(sigmask_copy);
  35. }
  36. ScopeGuard rollback_signal_mask([&]() {
  37. if (params.sigmask)
  38. current_thread->update_signal_mask(previous_signal_mask);
  39. });
  40. fd_set fds_read, fds_write, fds_except;
  41. size_t bytes_used = ceil_div(params.nfds, 8);
  42. if (bytes_used > sizeof(fds_read))
  43. return EINVAL;
  44. if (params.readfds && !copy_from_user(&fds_read, params.readfds, bytes_used))
  45. return EFAULT;
  46. if (params.writefds && !copy_from_user(&fds_write, params.writefds, bytes_used))
  47. return EFAULT;
  48. if (params.exceptfds && !copy_from_user(&fds_except, params.exceptfds, bytes_used))
  49. return EFAULT;
  50. Thread::SelectBlocker::FDVector fds_info;
  51. Vector<int, FD_SETSIZE> fds;
  52. for (int fd = 0; fd < params.nfds; fd++) {
  53. auto block_flags = BlockFlags::None;
  54. if (params.readfds && FD_ISSET(fd, &fds_read))
  55. block_flags |= BlockFlags::Read;
  56. if (params.writefds && FD_ISSET(fd, &fds_write))
  57. block_flags |= BlockFlags::Write;
  58. if (params.exceptfds && FD_ISSET(fd, &fds_except))
  59. block_flags |= BlockFlags::Exception;
  60. if (block_flags == BlockFlags::None)
  61. continue;
  62. auto description = file_description(fd);
  63. if (!description) {
  64. dbgln("sys$select: Bad fd number {}", fd);
  65. return EBADF;
  66. }
  67. fds_info.append({ description.release_nonnull(), block_flags });
  68. fds.append(fd);
  69. }
  70. if constexpr (IO_DEBUG || POLL_SELECT_DEBUG)
  71. dbgln("selecting on {} fds, timeout={}", fds_info.size(), params.timeout);
  72. if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) {
  73. dbgln_if(POLL_SELECT_DEBUG, "select was interrupted");
  74. return EINTR;
  75. }
  76. if (params.readfds)
  77. FD_ZERO(&fds_read);
  78. if (params.writefds)
  79. FD_ZERO(&fds_write);
  80. if (params.exceptfds)
  81. FD_ZERO(&fds_except);
  82. int marked_fd_count = 0;
  83. for (size_t i = 0; i < fds_info.size(); i++) {
  84. auto& fd_entry = fds_info[i];
  85. if (fd_entry.unblocked_flags == BlockFlags::None)
  86. continue;
  87. if (params.readfds && has_flag(fd_entry.unblocked_flags, BlockFlags::Read)) {
  88. FD_SET(fds[i], &fds_read);
  89. marked_fd_count++;
  90. }
  91. if (params.writefds && has_flag(fd_entry.unblocked_flags, BlockFlags::Write)) {
  92. FD_SET(fds[i], &fds_write);
  93. marked_fd_count++;
  94. }
  95. if (params.exceptfds && has_flag(fd_entry.unblocked_flags, BlockFlags::Exception)) {
  96. FD_SET(fds[i], &fds_except);
  97. marked_fd_count++;
  98. }
  99. }
  100. if (params.readfds && !copy_to_user(params.readfds, &fds_read, bytes_used))
  101. return EFAULT;
  102. if (params.writefds && !copy_to_user(params.writefds, &fds_write, bytes_used))
  103. return EFAULT;
  104. if (params.exceptfds && !copy_to_user(params.exceptfds, &fds_except, bytes_used))
  105. return EFAULT;
  106. return marked_fd_count;
  107. }
  108. KResultOr<int> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
  109. {
  110. REQUIRE_PROMISE(stdio);
  111. Syscall::SC_poll_params params;
  112. if (!copy_from_user(&params, user_params))
  113. return EFAULT;
  114. if (params.nfds >= m_max_open_file_descriptors)
  115. return ENOBUFS;
  116. Thread::BlockTimeout timeout;
  117. if (params.timeout) {
  118. auto timeout_time = copy_time_from_user(params.timeout);
  119. if (!timeout_time.has_value())
  120. return EFAULT;
  121. timeout = Thread::BlockTimeout(false, &timeout_time.value());
  122. }
  123. sigset_t sigmask = {};
  124. if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
  125. return EFAULT;
  126. Vector<pollfd> fds_copy;
  127. if (params.nfds > 0) {
  128. Checked nfds_checked = sizeof(pollfd);
  129. nfds_checked *= params.nfds;
  130. if (nfds_checked.has_overflow())
  131. return EFAULT;
  132. if (!fds_copy.try_resize(params.nfds))
  133. return ENOMEM;
  134. if (!copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value()))
  135. return EFAULT;
  136. }
  137. Thread::SelectBlocker::FDVector fds_info;
  138. for (size_t i = 0; i < params.nfds; i++) {
  139. auto& pfd = fds_copy[i];
  140. auto description = file_description(pfd.fd);
  141. if (!description) {
  142. dbgln("sys$poll: Bad fd number {}", pfd.fd);
  143. return EBADF;
  144. }
  145. BlockFlags block_flags = BlockFlags::Exception; // always want POLLERR, POLLHUP, POLLNVAL
  146. if (pfd.events & POLLIN)
  147. block_flags |= BlockFlags::Read;
  148. if (pfd.events & POLLOUT)
  149. block_flags |= BlockFlags::Write;
  150. if (pfd.events & POLLPRI)
  151. block_flags |= BlockFlags::ReadPriority;
  152. if (!fds_info.try_append({ description.release_nonnull(), block_flags }))
  153. return ENOMEM;
  154. }
  155. auto current_thread = Thread::current();
  156. u32 previous_signal_mask = 0;
  157. if (params.sigmask)
  158. previous_signal_mask = current_thread->update_signal_mask(sigmask);
  159. ScopeGuard rollback_signal_mask([&]() {
  160. if (params.sigmask)
  161. current_thread->update_signal_mask(previous_signal_mask);
  162. });
  163. if constexpr (IO_DEBUG || POLL_SELECT_DEBUG)
  164. dbgln("polling on {} fds, timeout={}", fds_info.size(), params.timeout);
  165. if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted())
  166. return EINTR;
  167. int fds_with_revents = 0;
  168. for (unsigned i = 0; i < params.nfds; ++i) {
  169. auto& pfd = fds_copy[i];
  170. auto& fds_entry = fds_info[i];
  171. pfd.revents = 0;
  172. if (fds_entry.unblocked_flags == BlockFlags::None)
  173. continue;
  174. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Exception)) {
  175. if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadHangUp))
  176. pfd.revents |= POLLRDHUP;
  177. if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteError))
  178. pfd.revents |= POLLERR;
  179. if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteHangUp))
  180. pfd.revents |= POLLNVAL;
  181. } else {
  182. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Read)) {
  183. VERIFY(pfd.events & POLLIN);
  184. pfd.revents |= POLLIN;
  185. }
  186. if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadPriority)) {
  187. VERIFY(pfd.events & POLLPRI);
  188. pfd.revents |= POLLPRI;
  189. }
  190. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Write)) {
  191. VERIFY(pfd.events & POLLOUT);
  192. pfd.revents |= POLLOUT;
  193. }
  194. }
  195. if (pfd.revents)
  196. fds_with_revents++;
  197. }
  198. if (params.nfds > 0 && !copy_to_user(&params.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd)))
  199. return EFAULT;
  200. return fds_with_revents;
  201. }
  202. }