diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 908145eb55..1244c73886 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1441,16 +1441,15 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) } } - current->m_waitee_pid = waitee; - current->m_wait_options = options; - current->block(Thread::State::BlockedWait); + pid_t waitee_pid = waitee; + current->block(*new Thread::ThreadBlockerWait(options, waitee_pid)); if (current->m_was_interrupted_while_blocked) return -EINTR; InterruptDisabler disabler; // NOTE: If waitee was -1, m_waitee_pid will have been filled in by the scheduler. - Process* waitee_process = Process::from_pid(current->m_waitee_pid); + Process* waitee_process = Process::from_pid(waitee_pid); ASSERT(waitee_process); if (waitee_process->is_dead()) { exit_status = reap(*waitee_process); @@ -1458,7 +1457,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) ASSERT(waitee_process->main_thread().state() == Thread::State::Stopped); exit_status = 0x7f; } - return current->m_waitee_pid; + return waitee_pid; } enum class KernelMemoryCheckResult { diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index fe85c386b7..0b57e72a63 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -172,11 +172,39 @@ bool Thread::ThreadBlockerSelect::should_unblock(Thread& thread, time_t now_sec, return false; } +Thread::ThreadBlockerWait::ThreadBlockerWait(int wait_options, pid_t& waitee_pid) + : m_wait_options(wait_options) + , m_waitee_pid(waitee_pid) +{ +} + +bool Thread::ThreadBlockerWait::should_unblock(Thread& thread, time_t, long) +{ + bool should_unblock = false; + thread.process().for_each_child([&](Process& child) { + if (m_waitee_pid != -1 && m_waitee_pid != child.pid()) + return IterationDecision::Continue; + + bool child_exited = child.is_dead(); + bool child_stopped = child.main_thread().state() == Thread::State::Stopped; + + bool wait_finished = ((m_wait_options & WEXITED) && child_exited) + || ((m_wait_options & WSTOPPED) && child_stopped); + + if (!wait_finished) + return IterationDecision::Continue; + + m_waitee_pid = child.pid(); + should_unblock = true; + return IterationDecision::Break; + }); + return should_unblock; +} + // 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) { - auto& process = this->process(); switch (state()) { case Thread::__Begin_Blocked_States__: case Thread::__End_Blocked_States__: @@ -191,25 +219,6 @@ void Thread::consider_unblock(time_t now_sec, long now_usec) case Thread::BlockedSignal: /* don't know, don't care */ return; - case Thread::BlockedWait: - process.for_each_child([&](Process& child) { - if (waitee_pid() != -1 && waitee_pid() != child.pid()) - return IterationDecision::Continue; - - bool child_exited = child.is_dead(); - bool child_stopped = child.main_thread().state() == Thread::State::Stopped; - - bool wait_finished = ((m_wait_options & WEXITED) && child_exited) - || ((m_wait_options & WSTOPPED) && child_stopped); - - if (!wait_finished) - return IterationDecision::Continue; - - m_waitee_pid = child.pid(); - unblock(); - return IterationDecision::Break; - }); - return; case Thread::BlockedCondition: ASSERT(m_blocker); if (m_blocker->should_unblock(*this, now_sec, now_usec)) { diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index 862aecd311..41ff119c18 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -162,8 +162,6 @@ const char* to_string(Thread::State state) return "Skip1"; case Thread::Skip0SchedulerPasses: return "Skip0"; - case Thread::BlockedWait: - return "Wait"; case Thread::BlockedSignal: return "Signal"; case Thread::BlockedLurking: diff --git a/Kernel/Thread.h b/Kernel/Thread.h index f356deccad..c1b1b9b7a5 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -65,7 +65,6 @@ public: __Begin_Blocked_States__, BlockedLurking, - BlockedWait, BlockedSignal, BlockedCondition, __End_Blocked_States__ @@ -147,6 +146,16 @@ public: const Vector& m_select_exceptional_fds; }; + class ThreadBlockerWait : public ThreadBlocker { + public: + ThreadBlockerWait(int wait_options, pid_t& waitee_pid); + virtual bool should_unblock(Thread&, time_t, long) override; + + private: + int m_wait_options { 0 }; + pid_t& m_waitee_pid; + }; + void did_schedule() { ++m_times_scheduled; } u32 times_scheduled() const { return m_times_scheduled; } @@ -164,7 +173,6 @@ public: TSS32& tss() { return m_tss; } State state() const { return m_state; } u32 ticks() const { return m_ticks; } - pid_t waitee_pid() const { return m_waitee_pid; } u64 sleep(u32 ticks); void block(Thread::State); @@ -250,8 +258,6 @@ private: u32 m_kernel_stack_base { 0 }; RefPtr m_kernel_stack_region; RefPtr m_kernel_stack_for_signal_handler_region; - pid_t m_waitee_pid { -1 }; - int m_wait_options { 0 }; SignalActionData m_signal_action_data[32]; Region* m_signal_stack_user_region { nullptr }; OwnPtr m_blocker;