diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 5798aa0940..908145eb55 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1792,13 +1792,17 @@ int Process::sys$select(const Syscall::SC_select_params* params) if (params->nfds < 0) return -EINVAL; + timeval timeout; + bool select_has_timeout = false; if (params->timeout && (params->timeout->tv_sec || params->timeout->tv_usec)) { - timeval_add(kgettimeofday(), *params->timeout, current->m_select_timeout); - current->m_select_has_timeout = true; - } else { - current->m_select_has_timeout = false; + timeval_add(kgettimeofday(), *params->timeout, timeout); + select_has_timeout = true; } + Vector rfds; + Vector wfds; + Vector efds; + auto transfer_fds = [&](auto* fds, auto& vector) -> int { vector.clear_with_capacity(); if (!fds) @@ -1812,19 +1816,19 @@ int Process::sys$select(const Syscall::SC_select_params* params) } return 0; }; - if (int error = transfer_fds(params->writefds, current->m_select_write_fds)) + if (int error = transfer_fds(params->writefds, wfds)) return error; - if (int error = transfer_fds(params->readfds, current->m_select_read_fds)) + if (int error = transfer_fds(params->readfds, rfds)) return error; - if (int error = transfer_fds(params->exceptfds, current->m_select_exceptional_fds)) + if (int error = transfer_fds(params->exceptfds, efds)) return error; #if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT) - dbgprintf("%s<%u> selecting on (read:%u, write:%u), timeout=%p\n", name().characters(), pid(), current->m_select_read_fds.size(), current->m_select_write_fds.size(), params->timeout); + dbgprintf("%s<%u> selecting on (read:%u, write:%u), timeout=%p\n", name().characters(), pid(), rfds.size(), wfds.size(), params->timeout); #endif - if (!params->timeout || current->m_select_has_timeout) - current->block(Thread::State::BlockedSelect); + if (!params->timeout || select_has_timeout) + current->block(*new Thread::ThreadBlockerSelect(timeout, select_has_timeout, rfds, wfds, efds)); int marked_fd_count = 0; auto mark_fds = [&](auto* fds, auto& vector, auto should_mark) { @@ -1838,8 +1842,8 @@ int Process::sys$select(const Syscall::SC_select_params* params) } } }; - mark_fds(params->readfds, current->m_select_read_fds, [](auto& description) { return description.can_read(); }); - mark_fds(params->writefds, current->m_select_write_fds, [](auto& description) { return description.can_write(); }); + mark_fds(params->readfds, rfds, [](auto& description) { return description.can_read(); }); + mark_fds(params->writefds, wfds, [](auto& description) { return description.can_write(); }); // FIXME: We should also mark params->exceptfds as appropriate. return marked_fd_count; } @@ -1849,15 +1853,18 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout) if (!validate_read_typed(fds)) return -EFAULT; - current->m_select_write_fds.clear_with_capacity(); - current->m_select_read_fds.clear_with_capacity(); + Vector rfds; + Vector wfds; + for (int i = 0; i < nfds; ++i) { if (fds[i].events & POLLIN) - current->m_select_read_fds.append(fds[i].fd); + rfds.append(fds[i].fd); if (fds[i].events & POLLOUT) - current->m_select_write_fds.append(fds[i].fd); + wfds.append(fds[i].fd); } + timeval actual_timeout; + bool has_timeout = false; if (timeout >= 0) { // poll is in ms, we want s/us. struct timeval tvtimeout; @@ -1867,19 +1874,16 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout) timeout -= 1000; } tvtimeout.tv_usec = timeout * 1000; - timeval_add(kgettimeofday(), tvtimeout, current->m_select_timeout); - current->m_select_has_timeout = true; - } else { - current->m_select_has_timeout = false; + timeval_add(kgettimeofday(), tvtimeout, actual_timeout); + has_timeout = true; } #if defined(DEBUG_IO) || defined(DEBUG_POLL_SELECT) - dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), current->m_select_read_fds.size(), current->m_select_write_fds.size(), timeout); + dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), rfds.size(), wfds.size(), timeout); #endif - if (current->m_select_has_timeout || timeout < 0) { - current->block(Thread::State::BlockedSelect); - } + if (has_timeout|| timeout < 0) + current->block(*new Thread::ThreadBlockerSelect(actual_timeout, has_timeout, rfds, wfds, Vector())); int fds_with_revents = 0; diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index fa36a27ee8..fe85c386b7 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -65,7 +65,7 @@ Thread::ThreadBlockerAccept::ThreadBlockerAccept(const RefPtr& { } -bool Thread::ThreadBlockerAccept::should_unblock(time_t, long) +bool Thread::ThreadBlockerAccept::should_unblock(Thread&, time_t, long) { auto& description = *blocked_description(); auto& socket = *description.socket(); @@ -78,7 +78,7 @@ Thread::ThreadBlockerReceive::ThreadBlockerReceive(const RefPtr { } -bool Thread::ThreadBlockerReceive::should_unblock(time_t now_sec, long now_usec) +bool Thread::ThreadBlockerReceive::should_unblock(Thread&, time_t now_sec, long now_usec) { auto& description = *blocked_description(); auto& socket = *description.socket(); @@ -94,7 +94,7 @@ Thread::ThreadBlockerConnect::ThreadBlockerConnect(const RefPtr { } -bool Thread::ThreadBlockerConnect::should_unblock(time_t, long) +bool Thread::ThreadBlockerConnect::should_unblock(Thread&, time_t, long) { auto& description = *blocked_description(); auto& socket = *description.socket(); @@ -106,7 +106,7 @@ Thread::ThreadBlockerWrite::ThreadBlockerWrite(const RefPtr& de { } -bool Thread::ThreadBlockerWrite::should_unblock(time_t, long) +bool Thread::ThreadBlockerWrite::should_unblock(Thread&, time_t, long) { return blocked_description()->can_write(); } @@ -116,7 +116,7 @@ Thread::ThreadBlockerRead::ThreadBlockerRead(const RefPtr& desc { } -bool Thread::ThreadBlockerRead::should_unblock(time_t, long) +bool Thread::ThreadBlockerRead::should_unblock(Thread&, time_t, long) { // FIXME: Block until the amount of data wanted is available. return blocked_description()->can_read(); @@ -128,7 +128,7 @@ Thread::ThreadBlockerCondition::ThreadBlockerCondition(Function &conditi ASSERT(m_block_until_condition); } -bool Thread::ThreadBlockerCondition::should_unblock(time_t, long) +bool Thread::ThreadBlockerCondition::should_unblock(Thread&, time_t, long) { return m_block_until_condition(); } @@ -138,11 +138,40 @@ Thread::ThreadBlockerSleep::ThreadBlockerSleep(u64 wakeup_time) { } -bool Thread::ThreadBlockerSleep::should_unblock(time_t, long) +bool Thread::ThreadBlockerSleep::should_unblock(Thread&, time_t, long) { return m_wakeup_time <= g_uptime; } +Thread::ThreadBlockerSelect::ThreadBlockerSelect(const timeval& tv, bool select_has_timeout, const Vector& read_fds, const Vector& write_fds, const Vector& except_fds) + : m_select_timeout(tv) + , m_select_has_timeout(select_has_timeout) + , m_select_read_fds(read_fds) + , m_select_write_fds(write_fds) + , m_select_exceptional_fds(except_fds) +{ +} + +bool Thread::ThreadBlockerSelect::should_unblock(Thread& thread, time_t now_sec, long now_usec) +{ + if (m_select_has_timeout) { + if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec >= m_select_timeout.tv_usec)) + return true; + } + + auto& process = thread.process(); + for (int fd : m_select_read_fds) { + if (process.m_fds[fd].description->can_read()) + return true; + } + for (int fd : m_select_write_fds) { + if (process.m_fds[fd].description->can_write()) + return true; + } + + return false; +} + // Called by the scheduler on threads that are blocked for some reason. // Make a decision as to whether to unblock them or not. void Thread::consider_unblock(time_t now_sec, long now_usec) @@ -181,29 +210,9 @@ void Thread::consider_unblock(time_t now_sec, long now_usec) return IterationDecision::Break; }); return; - case Thread::BlockedSelect: - if (m_select_has_timeout) { - if (now_sec > m_select_timeout.tv_sec || (now_sec == m_select_timeout.tv_sec && now_usec >= m_select_timeout.tv_usec)) { - unblock(); - return; - } - } - for (int fd : m_select_read_fds) { - if (process.m_fds[fd].description->can_read()) { - unblock(); - return; - } - } - for (int fd : m_select_write_fds) { - if (process.m_fds[fd].description->can_write()) { - unblock(); - return; - } - } - return; case Thread::BlockedCondition: ASSERT(m_blocker); - if (m_blocker->should_unblock(now_sec, now_usec)) { + if (m_blocker->should_unblock(*this, now_sec, now_usec)) { unblock(); m_blocker = nullptr; } diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index c5866fe888..862aecd311 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -166,8 +166,6 @@ const char* to_string(Thread::State state) return "Wait"; case Thread::BlockedSignal: return "Signal"; - case Thread::BlockedSelect: - return "Select"; case Thread::BlockedLurking: return "Lurking"; case Thread::BlockedCondition: diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 92d67d80bc..f356deccad 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -67,7 +67,6 @@ public: BlockedLurking, BlockedWait, BlockedSignal, - BlockedSelect, BlockedCondition, __End_Blocked_States__ }; @@ -75,7 +74,7 @@ public: class ThreadBlocker { public: virtual ~ThreadBlocker() {} - virtual bool should_unblock(time_t now_s, long us) = 0; + virtual bool should_unblock(Thread&, time_t now_s, long us) = 0; }; class ThreadBlockerFileDescription : public ThreadBlocker { @@ -90,37 +89,37 @@ public: class ThreadBlockerAccept : public ThreadBlockerFileDescription { public: ThreadBlockerAccept(const RefPtr& description); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; }; class ThreadBlockerReceive : public ThreadBlockerFileDescription { public: ThreadBlockerReceive(const RefPtr& description); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; }; class ThreadBlockerConnect : public ThreadBlockerFileDescription { public: ThreadBlockerConnect(const RefPtr& description); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; }; class ThreadBlockerWrite : public ThreadBlockerFileDescription { public: ThreadBlockerWrite(const RefPtr& description); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; }; class ThreadBlockerRead : public ThreadBlockerFileDescription { public: ThreadBlockerRead(const RefPtr& description); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; }; class ThreadBlockerCondition : public ThreadBlocker { public: ThreadBlockerCondition(Function &condition); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; private: Function m_block_until_condition; @@ -129,12 +128,25 @@ public: class ThreadBlockerSleep : public ThreadBlocker { public: ThreadBlockerSleep(u64 wakeup_time); - virtual bool should_unblock(time_t, long) override; + virtual bool should_unblock(Thread&, time_t, long) override; private: u64 m_wakeup_time { 0 }; }; + class ThreadBlockerSelect : public ThreadBlocker { + public: + ThreadBlockerSelect(const timeval& tv, bool select_has_timeout, const Vector& read_fds, const Vector& write_fds, const Vector& except_fds); + virtual bool should_unblock(Thread&, time_t, long) override; + + private: + timeval m_select_timeout; + bool m_select_has_timeout { false }; + const Vector& m_select_read_fds; + const Vector& m_select_write_fds; + const Vector& m_select_exceptional_fds; + }; + void did_schedule() { ++m_times_scheduled; } u32 times_scheduled() const { return m_times_scheduled; } @@ -240,17 +252,12 @@ private: RefPtr m_kernel_stack_for_signal_handler_region; pid_t m_waitee_pid { -1 }; int m_wait_options { 0 }; - timeval m_select_timeout; SignalActionData m_signal_action_data[32]; Region* m_signal_stack_user_region { nullptr }; OwnPtr m_blocker; - Vector m_select_read_fds; - Vector m_select_write_fds; - Vector m_select_exceptional_fds; FPUState* m_fpu_state { nullptr }; InlineLinkedList* m_thread_list { nullptr }; State m_state { Invalid }; - bool m_select_has_timeout { false }; bool m_has_used_fpu { false }; bool m_was_interrupted_while_blocked { false }; };