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:
parent
4616997f5b
commit
42eb0a1d74
@ -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;
|
||||
|
||||
|
@ -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 (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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user