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;
});
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->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);
while (thread->state != ThreadState::Exited)
{
if (options & WNOHANG) return err(EAGAIN);
kernel_sleep(10);
}
if (options & WNOHANG) return err(EAGAIN);
if (thread->state != ThreadState::Exited) kernel_wait(pid);
check(thread->state == ThreadState::Exited);
}
else if (pid == -1)
{
if (!Scheduler::has_children(current)) return err(ECHILD);
Option<Thread*> child;
while (child = Scheduler::find_exited_child(current), !child.has_value())
auto child = Scheduler::find_exited_child(current);
if (!child.has_value())
{
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
return err(ENOTSUP);
current->child_being_waited_for = {};
int status = (int)thread->status;
u64 id = thread->id;

View File

@ -325,6 +325,13 @@ void kernel_sleep(u64 ms)
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()
{
g_current->state = ThreadState::Dying;

View File

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

View File

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