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;
|
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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user