select.cpp 8.2 KB

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