mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:47:45 +00:00
Kernel: Add support for the WSTOPPED flag to the waitpid() syscall.
This makes waitpid() return when a child process is stopped via a signal. Use this in Shell to catch stopped children and return control to the command line. :^) Fixes #298.
This commit is contained in:
parent
de03b72979
commit
3073ea7d84
6 changed files with 44 additions and 20 deletions
|
@ -1393,8 +1393,12 @@ int Process::reap(Process& process)
|
||||||
pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
||||||
{
|
{
|
||||||
dbgprintf("sys$waitpid(%d, %p, %d)\n", waitee, wstatus, 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 (wstatus)
|
||||||
if (!validate_write_typed(wstatus))
|
if (!validate_write_typed(wstatus))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -1409,6 +1413,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options & WNOHANG) {
|
if (options & WNOHANG) {
|
||||||
|
// FIXME: Figure out what WNOHANG should do with stopped children.
|
||||||
if (waitee == -1) {
|
if (waitee == -1) {
|
||||||
pid_t reaped_pid = 0;
|
pid_t reaped_pid = 0;
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
|
@ -1417,7 +1422,7 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
||||||
reaped_pid = process.pid();
|
reaped_pid = process.pid();
|
||||||
exit_status = reap(process);
|
exit_status = reap(process);
|
||||||
}
|
}
|
||||||
return true;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
return reaped_pid;
|
return reaped_pid;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1435,17 +1440,22 @@ pid_t Process::sys$waitpid(pid_t waitee, int* wstatus, int options)
|
||||||
}
|
}
|
||||||
|
|
||||||
current->m_waitee_pid = waitee;
|
current->m_waitee_pid = waitee;
|
||||||
|
current->m_wait_options = options;
|
||||||
current->block(Thread::State::BlockedWait);
|
current->block(Thread::State::BlockedWait);
|
||||||
if (current->m_was_interrupted_while_blocked)
|
if (current->m_was_interrupted_while_blocked)
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
Process* waitee_process;
|
|
||||||
{
|
InterruptDisabler disabler;
|
||||||
InterruptDisabler disabler;
|
|
||||||
// NOTE: If waitee was -1, m_waitee will have been filled in by the scheduler.
|
// NOTE: If waitee was -1, m_waitee_pid will have been filled in by the scheduler.
|
||||||
waitee_process = Process::from_pid(current->m_waitee_pid);
|
Process* waitee_process = Process::from_pid(current->m_waitee_pid);
|
||||||
}
|
|
||||||
ASSERT(waitee_process);
|
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;
|
return current->m_waitee_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -411,7 +411,7 @@ inline void Process::for_each_child(Callback callback)
|
||||||
for (auto* process = g_processes->head(); process;) {
|
for (auto* process = g_processes->head(); process;) {
|
||||||
auto* next_process = process->next();
|
auto* next_process = process->next();
|
||||||
if (process->ppid() == my_pid) {
|
if (process->ppid() == my_pid) {
|
||||||
if (!callback(*process))
|
if (callback(*process) == IterationDecision::Break)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
process = next_process;
|
process = next_process;
|
||||||
|
|
|
@ -83,14 +83,21 @@ bool Scheduler::pick_next()
|
||||||
|
|
||||||
if (thread.state() == Thread::BlockedWait) {
|
if (thread.state() == Thread::BlockedWait) {
|
||||||
process.for_each_child([&](Process& child) {
|
process.for_each_child([&](Process& child) {
|
||||||
if (!child.is_dead())
|
if (thread.waitee_pid() != -1 && thread.waitee_pid() != child.pid())
|
||||||
return true;
|
return IterationDecision::Continue;
|
||||||
if (thread.waitee_pid() == -1 || thread.waitee_pid() == child.pid()) {
|
|
||||||
thread.m_waitee_pid = child.pid();
|
bool child_exited = child.is_dead();
|
||||||
thread.unblock();
|
bool child_stopped = child.main_thread().state() == Thread::State::Stopped;
|
||||||
return false;
|
|
||||||
}
|
bool wait_finished = ((thread.m_wait_options & WEXITED) && child_exited)
|
||||||
return true;
|
|| ((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;
|
return IterationDecision::Continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,7 @@ private:
|
||||||
RefPtr<Region> m_kernel_stack_region;
|
RefPtr<Region> m_kernel_stack_region;
|
||||||
RefPtr<Region> m_kernel_stack_for_signal_handler_region;
|
RefPtr<Region> m_kernel_stack_for_signal_handler_region;
|
||||||
pid_t m_waitee_pid { -1 };
|
pid_t m_waitee_pid { -1 };
|
||||||
|
int m_wait_options { 0 };
|
||||||
RefPtr<FileDescription> m_blocked_description;
|
RefPtr<FileDescription> m_blocked_description;
|
||||||
timeval m_select_timeout;
|
timeval m_select_timeout;
|
||||||
SignalActionData m_signal_action_data[32];
|
SignalActionData m_signal_action_data[32];
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
||||||
#define WNOHANG 1
|
#define WNOHANG 1
|
||||||
|
#define WUNTRACED 2
|
||||||
|
#define WSTOPPED WUNTRACED
|
||||||
|
#define WEXITED 4
|
||||||
|
#define WCONTINUED 8
|
||||||
|
|
||||||
#define R_OK 4
|
#define R_OK 4
|
||||||
#define W_OK 2
|
#define W_OK 2
|
||||||
|
|
|
@ -488,7 +488,7 @@ static int run_command(const String& cmd)
|
||||||
for (int i = 0; i < children.size(); ++i) {
|
for (int i = 0; i < children.size(); ++i) {
|
||||||
auto& child = children[i];
|
auto& child = children[i];
|
||||||
do {
|
do {
|
||||||
int rc = waitpid(child.pid, &wstatus, 0);
|
int rc = waitpid(child.pid, &wstatus, WEXITED | WSTOPPED);
|
||||||
if (rc < 0 && errno != EINTR) {
|
if (rc < 0 && errno != EINTR) {
|
||||||
if (errno != ECHILD)
|
if (errno != ECHILD)
|
||||||
perror("waitpid");
|
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));
|
printf("Shell: %s(%d) exited with status %d\n", child.name.characters(), child.pid, WEXITSTATUS(wstatus));
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
return_value = WEXITSTATUS(wstatus);
|
return_value = WEXITSTATUS(wstatus);
|
||||||
|
} else if (WIFSTOPPED(wstatus)) {
|
||||||
|
printf("Shell: %s(%d) stopped.\n", child.name.characters(), child.pid);
|
||||||
} else {
|
} else {
|
||||||
if (WIFSIGNALED(wstatus)) {
|
if (WIFSIGNALED(wstatus)) {
|
||||||
printf("Shell: %s(%d) exited due to signal '%s'\n", child.name.characters(), child.pid, strsignal(WTERMSIG(wstatus)));
|
printf("Shell: %s(%d) exited due to signal '%s'\n", child.name.characters(), child.pid, strsignal(WTERMSIG(wstatus)));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue