kernel+init+sh: Implement parent processes and waitpid(-1, ...)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
f084b57f39
commit
7efcc06090
@ -5,6 +5,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define xmknod(path, mode, maj, min) \
|
||||
@ -46,6 +47,5 @@ int main()
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
;
|
||||
while (1) { waitpid(-1, NULL, 0); }
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
||||
|
||||
thread->state = ThreadState::Runnable;
|
||||
thread->is_kernel = false;
|
||||
thread->parent_id = current->id;
|
||||
thread->fp_data.save();
|
||||
|
||||
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
|
||||
|
@ -7,6 +7,8 @@ Result<u64> sys_exit(Registers*, SyscallArgs args)
|
||||
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
Scheduler::for_each_child((pid_t)current->id, [](Thread* child) { child->parent_id = 1; });
|
||||
|
||||
current->status = status;
|
||||
current->state = ThreadState::Exited;
|
||||
|
||||
|
@ -9,13 +9,38 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
|
||||
int* status_ptr = (int*)args[1];
|
||||
int options = (int)args[2];
|
||||
|
||||
Thread* thread = TRY(Result<Thread*>::from_option(Scheduler::find_by_pid(pid), ESRCH));
|
||||
Thread* current = Scheduler::current();
|
||||
|
||||
Thread* thread;
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
thread = TRY(Result<Thread*>::from_option(Scheduler::find_by_pid(pid), ESRCH));
|
||||
|
||||
if (thread->parent_id != current->id) return err(ECHILD);
|
||||
|
||||
while (thread->state != ThreadState::Exited)
|
||||
{
|
||||
if (options & WNOHANG) return err(EAGAIN);
|
||||
kernel_sleep(10);
|
||||
}
|
||||
}
|
||||
else if (pid == -1)
|
||||
{
|
||||
if (!Scheduler::has_children((pid_t)current->id)) return err(ECHILD);
|
||||
|
||||
Option<Thread*> child;
|
||||
|
||||
while (child = Scheduler::find_exited_child((pid_t)current->id), !child.has_value())
|
||||
{
|
||||
if (options & WNOHANG) return err(EAGAIN);
|
||||
kernel_sleep(10);
|
||||
}
|
||||
|
||||
thread = child.value();
|
||||
}
|
||||
else
|
||||
return err(ENOTSUP);
|
||||
|
||||
int status = (int)thread->status;
|
||||
|
||||
@ -24,5 +49,5 @@ Result<u64> sys_waitpid(Registers*, SyscallArgs args)
|
||||
if (status_ptr)
|
||||
if (!MemoryManager::copy_to_user_typed(status_ptr, &status)) return err(EFAULT);
|
||||
|
||||
return (u64)pid;
|
||||
return thread->id;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ namespace Scheduler
|
||||
g_idle.set_ip((u64)CPU::idle_loop);
|
||||
g_idle.state = ThreadState::Idle;
|
||||
g_idle.is_kernel = true;
|
||||
g_idle.parent_id = 0;
|
||||
|
||||
g_idle.ticks_left = 1;
|
||||
|
||||
@ -64,6 +65,8 @@ namespace Scheduler
|
||||
|
||||
thread->stack = thread_stack;
|
||||
|
||||
thread->parent_id = 0;
|
||||
|
||||
thread->is_kernel = true;
|
||||
|
||||
g_threads.append(thread);
|
||||
@ -106,6 +109,7 @@ namespace Scheduler
|
||||
Thread* const thread = TRY(new_thread());
|
||||
|
||||
thread->is_kernel = false;
|
||||
thread->parent_id = 0;
|
||||
|
||||
auto guard = make_scope_guard([&] { delete thread; });
|
||||
|
||||
@ -264,6 +268,26 @@ namespace Scheduler
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool has_children(pid_t pid)
|
||||
{
|
||||
bool result { false };
|
||||
|
||||
for_each_child(pid, [&](Thread*) { result = true; });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Option<Thread*> find_exited_child(pid_t pid)
|
||||
{
|
||||
Option<Thread*> result;
|
||||
|
||||
for_each_child(pid, [&](Thread* child) {
|
||||
if (!result.has_value() && child->state == ThreadState::Exited) result = child;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void kernel_sleep(u64 ms)
|
||||
|
@ -28,6 +28,17 @@ namespace Scheduler
|
||||
LinkedList<Thread> check_for_dying_threads();
|
||||
|
||||
Option<Thread*> find_by_pid(pid_t pid);
|
||||
|
||||
template <typename Callback> void for_each_child(pid_t pid, Callback callback)
|
||||
{
|
||||
g_threads.for_each([&](Thread* thread) {
|
||||
if (thread->parent_id == (u64)pid) callback(thread);
|
||||
});
|
||||
}
|
||||
|
||||
bool has_children(pid_t pid);
|
||||
|
||||
Option<Thread*> find_exited_child(pid_t pid);
|
||||
}
|
||||
|
||||
extern "C" void kernel_yield();
|
||||
|
@ -42,6 +42,7 @@ struct Thread : public LinkedListNode<Thread>
|
||||
Registers regs;
|
||||
|
||||
u64 id;
|
||||
u64 parent_id;
|
||||
|
||||
u64 ticks = 0;
|
||||
u64 ticks_in_user = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user