summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.cpp30
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Scheduler.cpp23
-rw-r--r--Kernel/Thread.h1
-rw-r--r--Kernel/UnixTypes.h4
-rw-r--r--Shell/main.cpp4
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)));