kernel: Freeze waitpid()'s calling thread until a child tells us it's done, instead of polling it every 10 ms

This commit is contained in:
apio 2023-05-04 23:03:31 +02:00
parent 4616997f5b
commit 42eb0a1d74
Signed by: apio
GPG Key ID: B8A7D06E42258954
5 changed files with 37 additions and 11 deletions

View File

@ -12,6 +12,17 @@ Result<u64> sys_exit(Registers*, SyscallArgs args)
return true; return true;
}); });
auto* parent = current->parent;
if (parent && parent->state == ThreadState::Waiting)
{
auto child = *parent->child_being_waited_for;
if (child == -1 || child == (pid_t)current->id)
{
parent->child_being_waited_for = (pid_t)current->id;
parent->state = ThreadState::Runnable;
}
}
current->status = status; current->status = status;
current->state = ThreadState::Exited; current->state = ThreadState::Exited;

View File

@ -19,29 +19,34 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
if (thread->parent && thread->parent != current) return err(ECHILD); if (thread->parent && thread->parent != current) return err(ECHILD);
while (thread->state != ThreadState::Exited) if (options & WNOHANG) return err(EAGAIN);
{
if (options & WNOHANG) return err(EAGAIN); if (thread->state != ThreadState::Exited) kernel_wait(pid);
kernel_sleep(10); check(thread->state == ThreadState::Exited);
}
} }
else if (pid == -1) else if (pid == -1)
{ {
if (!Scheduler::has_children(current)) return err(ECHILD); if (!Scheduler::has_children(current)) return err(ECHILD);
Option<Thread*> child; auto child = Scheduler::find_exited_child(current);
if (!child.has_value())
while (child = Scheduler::find_exited_child(current), !child.has_value())
{ {
if (options & WNOHANG) return err(EAGAIN); if (options & WNOHANG) return err(EAGAIN);
kernel_sleep(10);
}
thread = child.value(); kernel_wait(pid);
check(current->child_being_waited_for.value_or(-1) != -1);
thread = TRY(Result<Thread*>::from_option(Scheduler::find_by_pid(*current->child_being_waited_for), ESRCH));
check(thread->state == ThreadState::Exited);
}
else
thread = child.value();
} }
else else
return err(ENOTSUP); return err(ENOTSUP);
current->child_being_waited_for = {};
int status = (int)thread->status; int status = (int)thread->status;
u64 id = thread->id; u64 id = thread->id;

View File

@ -325,6 +325,13 @@ void kernel_sleep(u64 ms)
kernel_yield(); kernel_yield();
} }
void kernel_wait(pid_t pid)
{
g_current->child_being_waited_for = pid;
g_current->state = ThreadState::Waiting;
kernel_yield();
}
[[noreturn]] void kernel_exit() [[noreturn]] void kernel_exit()
{ {
g_current->state = ThreadState::Dying; g_current->state = ThreadState::Dying;

View File

@ -48,5 +48,6 @@ namespace Scheduler
} }
extern "C" void kernel_yield(); extern "C" void kernel_yield();
void kernel_wait(pid_t pid);
void kernel_sleep(u64 ms); void kernel_sleep(u64 ms);
[[noreturn]] void kernel_exit(); [[noreturn]] void kernel_exit();

View File

@ -22,6 +22,7 @@ enum class ThreadState
Idle, Idle,
Runnable, Runnable,
Sleeping, Sleeping,
Waiting,
Exited, Exited,
Dying Dying
}; };
@ -90,6 +91,7 @@ struct Thread : public LinkedListNode<Thread>
SharedPtr<VFS::Inode> current_directory = {}; SharedPtr<VFS::Inode> current_directory = {};
Thread* parent { nullptr }; Thread* parent { nullptr };
Option<pid_t> child_being_waited_for = {};
PageDirectory* directory; PageDirectory* directory;