diff options
-rw-r--r-- | Kernel/Process.cpp | 30 | ||||
-rw-r--r-- | Kernel/Process.h | 2 | ||||
-rw-r--r-- | Kernel/Scheduler.cpp | 23 | ||||
-rw-r--r-- | Kernel/Thread.h | 1 | ||||
-rw-r--r-- | Kernel/UnixTypes.h | 4 | ||||
-rw-r--r-- | Shell/main.cpp | 4 |
6 files changed, 44 insertions, 20 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 2c071bd0f7..9d7031da44 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1393,8 +1393,12 @@ int Process::reap(Process& process) pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) { dbgprintf("sys$waitpid(%d, %p, %d)\n", waitee, wstatus, options); - // FIXME: Respect options - (void)options; + + if (!options) { + // FIXME: This can't be right.. can it? Figure out how this should actually work. + options = WEXITED; + } + if (wstatus) if (!validate_write_typed(wstatus)) return -EFAULT; @@ -1409,6 +1413,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) } if (options & WNOHANG) { + // FIXME: Figure out what WNOHANG should do with stopped children. if (waitee == -1) { pid_t reaped_pid = 0; InterruptDisabler disabler; @@ -1417,7 +1422,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options) reaped_pid = process.pid(); exit_status = reap(process); } - return true; + return IterationDecision::Continue; }); return reaped_pid; } else { @@ -1435,17 +1440,22 @@ 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); if (current->m_was_interrupted_while_blocked) return -EINTR; - Process* waitee_process; - { - InterruptDisabler disabler; - // NOTE: If waitee was -1, m_waitee will have been filled in by the scheduler. - waitee_process = Process::from_pid(current->m_waitee_pid); - } + + 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); ASSERT(waitee_process); - exit_status = reap(*waitee_process); + if (waitee_process->is_dead()) { + exit_status = reap(*waitee_process); + } else { + ASSERT(waitee_process->main_thread().state() == Thread::State::Stopped); + exit_status = 0x7f; + } return current->m_waitee_pid; } diff --git a/Kernel/Process.h b/Kernel/Process.h index c12814a37c..3d31f354d8 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -411,7 +411,7 @@ inline void Process::for_each_child(Callback callback) for (auto* process = g_processes->head(); process;) { auto* next_process = process->next(); if (process->ppid() == my_pid) { - if (!callback(*process)) + if (callback(*process) == IterationDecision::Break) break; } process = next_process; diff --git a/Kernel/Scheduler.cpp b/Kernel/Scheduler.cpp index 59ae380be0..479bc4be46 100644 --- a/Kernel/Scheduler.cpp +++ b/Kernel/Scheduler.cpp @@ -83,14 +83,21 @@ bool Scheduler::pick_next() if (thread.state() == Thread::BlockedWait) { process.for_each_child([&](Process& child) { - if (!child.is_dead()) - return true; - if (thread.waitee_pid() == -1 || thread.waitee_pid() == child.pid()) { - thread.m_waitee_pid = child.pid(); - thread.unblock(); - return false; - } - return true; + if (thread.waitee_pid() != -1 && thread.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 = ((thread.m_wait_options & WEXITED) && child_exited) + || ((thread.m_wait_options & WSTOPPED) && child_stopped); + + if (!wait_finished) + return IterationDecision::Continue; + + thread.m_waitee_pid = child.pid(); + thread.unblock(); + return IterationDecision::Break; }); return IterationDecision::Continue; } diff --git a/Kernel/Thread.h b/Kernel/Thread.h index 225152f93e..d955d207df 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -182,6 +182,7 @@ private: RefPtr<Region> m_kernel_stack_region; RefPtr<Region> m_kernel_stack_for_signal_handler_region; pid_t m_waitee_pid { -1 }; + int m_wait_options { 0 }; RefPtr<FileDescription> m_blocked_description; timeval m_select_timeout; SignalActionData m_signal_action_data[32]; diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 063ee96b36..09ed93dda0 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -3,6 +3,10 @@ #include <AK/Types.h> #define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED WUNTRACED +#define WEXITED 4 +#define WCONTINUED 8 #define R_OK 4 #define W_OK 2 diff --git a/Shell/main.cpp b/Shell/main.cpp index 117c2e0592..edad94f0d1 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -488,7 +488,7 @@ static int run_command(const String& cmd) for (int i = 0; i < children.size(); ++i) { auto& child = children[i]; do { - int rc = waitpid(child.pid, &wstatus, 0); + int rc = waitpid(child.pid, &wstatus, WEXITED | WSTOPPED); if (rc < 0 && errno != EINTR) { if (errno != ECHILD) perror("waitpid"); @@ -499,6 +499,8 @@ static int run_command(const String& cmd) printf("Shell: %s(%d) exited with status %d\n", child.name.characters(), child.pid, WEXITSTATUS(wstatus)); if (i == 0) return_value = WEXITSTATUS(wstatus); + } else if (WIFSTOPPED(wstatus)) { + printf("Shell: %s(%d) stopped.\n", child.name.characters(), child.pid); } else { if (WIFSIGNALED(wstatus)) { printf("Shell: %s(%d) exited due to signal '%s'\n", child.name.characters(), child.pid, strsignal(WTERMSIG(wstatus))); |