select.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. 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. if (!fds_info.try_append({ description.release_nonnull(), block_flags }))
  68. return ENOMEM;
  69. if (!fds.try_append(fd))
  70. return ENOMEM;
  71. }
  72. if constexpr (IO_DEBUG || POLL_SELECT_DEBUG)
  73. dbgln("selecting on {} fds, timeout={}", fds_info.size(), params.timeout);
  74. if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted()) {
  75. dbgln_if(POLL_SELECT_DEBUG, "select was interrupted");
  76. return EINTR;
  77. }
  78. if (params.readfds)
  79. FD_ZERO(&fds_read);
  80. if (params.writefds)
  81. FD_ZERO(&fds_write);
  82. if (params.exceptfds)
  83. FD_ZERO(&fds_except);
  84. int marked_fd_count = 0;
  85. for (size_t i = 0; i < fds_info.size(); i++) {
  86. auto& fd_entry = fds_info[i];
  87. if (fd_entry.unblocked_flags == BlockFlags::None)
  88. continue;
  89. if (params.readfds && has_flag(fd_entry.unblocked_flags, BlockFlags::Read)) {
  90. FD_SET(fds[i], &fds_read);
  91. marked_fd_count++;
  92. }
  93. if (params.writefds && has_flag(fd_entry.unblocked_flags, BlockFlags::Write)) {
  94. FD_SET(fds[i], &fds_write);
  95. marked_fd_count++;
  96. }
  97. if (params.exceptfds && has_flag(fd_entry.unblocked_flags, BlockFlags::Exception)) {
  98. FD_SET(fds[i], &fds_except);
  99. marked_fd_count++;
  100. }
  101. }
  102. if (params.readfds && !copy_to_user(params.readfds, &fds_read, bytes_used))
  103. return EFAULT;
  104. if (params.writefds && !copy_to_user(params.writefds, &fds_write, bytes_used))
  105. return EFAULT;
  106. if (params.exceptfds && !copy_to_user(params.exceptfds, &fds_except, bytes_used))
  107. return EFAULT;
  108. return marked_fd_count;
  109. }
  110. KResultOr<FlatPtr> Process::sys$poll(Userspace<const Syscall::SC_poll_params*> user_params)
  111. {
  112. REQUIRE_PROMISE(stdio);
  113. Syscall::SC_poll_params params;
  114. if (!copy_from_user(&params, user_params))
  115. return EFAULT;
  116. if (params.nfds >= m_max_open_file_descriptors)
  117. return ENOBUFS;
  118. Thread::BlockTimeout timeout;
  119. if (params.timeout) {
  120. auto timeout_time = copy_time_from_user(params.timeout);
  121. if (!timeout_time.has_value())
  122. return EFAULT;
  123. timeout = Thread::BlockTimeout(false, &timeout_time.value());
  124. }
  125. sigset_t sigmask = {};
  126. if (params.sigmask && !copy_from_user(&sigmask, params.sigmask))
  127. return EFAULT;
  128. Vector<pollfd, FD_SETSIZE> fds_copy;
  129. if (params.nfds > 0) {
  130. Checked nfds_checked = sizeof(pollfd);
  131. nfds_checked *= params.nfds;
  132. if (nfds_checked.has_overflow())
  133. return EFAULT;
  134. if (!fds_copy.try_resize(params.nfds))
  135. return ENOMEM;
  136. if (!copy_from_user(fds_copy.data(), &params.fds[0], nfds_checked.value()))
  137. return EFAULT;
  138. }
  139. Thread::SelectBlocker::FDVector fds_info;
  140. for (size_t i = 0; i < params.nfds; i++) {
  141. auto& pfd = fds_copy[i];
  142. auto description = file_description(pfd.fd);
  143. if (!description) {
  144. dbgln("sys$poll: Bad fd number {}", pfd.fd);
  145. return EBADF;
  146. }
  147. BlockFlags block_flags = BlockFlags::Exception; // always want POLLERR, POLLHUP, POLLNVAL
  148. if (pfd.events & POLLIN)
  149. block_flags |= BlockFlags::Read;
  150. if (pfd.events & POLLOUT)
  151. block_flags |= BlockFlags::Write;
  152. if (pfd.events & POLLPRI)
  153. block_flags |= BlockFlags::ReadPriority;
  154. if (!fds_info.try_append({ description.release_nonnull(), block_flags }))
  155. return ENOMEM;
  156. }
  157. auto current_thread = Thread::current();
  158. u32 previous_signal_mask = 0;
  159. if (params.sigmask)
  160. previous_signal_mask = current_thread->update_signal_mask(sigmask);
  161. ScopeGuard rollback_signal_mask([&]() {
  162. if (params.sigmask)
  163. current_thread->update_signal_mask(previous_signal_mask);
  164. });
  165. if constexpr (IO_DEBUG || POLL_SELECT_DEBUG)
  166. dbgln("polling on {} fds, timeout={}", fds_info.size(), params.timeout);
  167. if (current_thread->block<Thread::SelectBlocker>(timeout, fds_info).was_interrupted())
  168. return EINTR;
  169. int fds_with_revents = 0;
  170. for (unsigned i = 0; i < params.nfds; ++i) {
  171. auto& pfd = fds_copy[i];
  172. auto& fds_entry = fds_info[i];
  173. pfd.revents = 0;
  174. if (fds_entry.unblocked_flags == BlockFlags::None)
  175. continue;
  176. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Exception)) {
  177. if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadHangUp))
  178. pfd.revents |= POLLRDHUP;
  179. if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteError))
  180. pfd.revents |= POLLERR;
  181. if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteHangUp))
  182. pfd.revents |= POLLNVAL;
  183. } else {
  184. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Read)) {
  185. VERIFY(pfd.events & POLLIN);
  186. pfd.revents |= POLLIN;
  187. }
  188. if (has_flag(fds_entry.unblocked_flags, BlockFlags::ReadPriority)) {
  189. VERIFY(pfd.events & POLLPRI);
  190. pfd.revents |= POLLPRI;
  191. }
  192. if (has_flag(fds_entry.unblocked_flags, BlockFlags::Write)) {
  193. VERIFY(pfd.events & POLLOUT);
  194. pfd.revents |= POLLOUT;
  195. }
  196. }
  197. if (pfd.revents)
  198. fds_with_revents++;
  199. }
  200. if (params.nfds > 0 && !copy_to_user(&params.fds[0], fds_copy.data(), params.nfds * sizeof(pollfd)))
  201. return EFAULT;
  202. return fds_with_revents;
  203. }
  204. }