Add waitpid syscall

This commit is contained in:
Mark
2020-01-05 14:44:07 +02:00
parent a83f7ddb45
commit bc1ab6776c
8 changed files with 113 additions and 18 deletions
+1
View File
@@ -24,3 +24,4 @@
#define SYSCALL_NRX_OPENPTY 118
#define SYSCALL_NRX_SIGRET 119
#define SYSCALL_NRX_WAITPID 247
+5
View File
@@ -4,6 +4,8 @@
#define THREAD_KERNEL (1 << 31)
#define THREAD_CTX_ONLY (1 << 30)
// Thread is stopped, wait()ed by its parent and ready for reaping
#define THREAD_DONE_WAITING (1 << 5)
// Well, this is actually the opposite - not a child waiting to be
// wait()ed by a parent (as I have no wait() yet), but rather a
// parent awaiting child process tree termination.
@@ -34,6 +36,8 @@ struct thread {
uint64_t flags;
uint32_t pid;
int exit_code;
struct vfs_ioctx ioctx;
struct ofile fds[4];
@@ -66,5 +70,6 @@ int thread_init(struct thread *t,
uint32_t flags,
void *arg);
void thread_cleanup(struct thread *t);
void thread_terminate(struct thread *t);
void thread_signal(struct thread *t, int signum);
+53 -17
View File
@@ -294,6 +294,25 @@ static void thread_unchild(struct thread *thr) {
}
}
// Called after parent is done waiting
void thread_terminate(struct thread *thr) {
_assert(thr->flags & THREAD_STOPPED);
_assert(thr->flags & THREAD_DONE_WAITING);
if (!thr->child) {
// Remove from parent's "child" list
thread_unchild(thr);
kdebug("Thread cleanup: %d\n", thr->pid);
thread_cleanup(thr);
} else {
// TODO: add to some kind of "zombie" queue
// mark children as "zombie-children" to notify parent task
kdebug("Couldn't terminate thread %d: has children\n", thr->pid);
thr->flags |= THREAD_ZOMBIE;
}
}
void sched_remove_from(int cpu, struct thread *thr) {
struct thread *prev = thr->prev;
struct thread *next = thr->next;
@@ -316,23 +335,9 @@ void sched_remove_from(int cpu, struct thread *thr) {
thr->next = NULL;
thr->prev = NULL;
if (!thr->child) {
// Remove from parent's "child" list
thread_unchild(thr);
// Parents have to wait for their children to terminate
if (cpu == (int) get_cpu()->processor_id) {
// No need for IPI - just cleanup
kdebug("Thread cleanup: %d on cpu%d\n", thr->pid, cpu);
thread_cleanup(thr);
} else {
// TODO: make other cpus schedule a new thread if they're running a stopped one
}
} else {
// TODO: add to some kind of "zombie" queue
// mark children as "zombie-children" to notify parent task
kdebug("Couldn't terminate thread %d: has children\n", thr->pid);
thr->flags |= THREAD_ZOMBIE;
// TODO: child process sends SIGCHLD to its parent (ignored by default)
if (thr->pid == 1) {
thread_terminate(thr);
}
}
@@ -362,10 +367,41 @@ void sched_reboot(unsigned int cmd) {
static uint64_t debug_last_tick = 0;
static void debug_thread_tree(struct thread *thr, size_t depth) {
for (size_t i = 0; i < depth; ++i) {
debugs(DEBUG_DEFAULT, " ");
}
debugf(DEBUG_DEFAULT, "Thread %d", thr->pid);
if (thr->flags & THREAD_ZOMBIE) {
debugc(DEBUG_DEFAULT, 'z');
}
if (thr->flags & THREAD_STOPPED) {
debugc(DEBUG_DEFAULT, 's');
}
if (thr->child) {
debugs(DEBUG_DEFAULT, " {\n");
for (struct thread *ch = thr->child; ch; ch = ch->next_child) {
debug_thread_tree(ch, depth + 1);
}
for (size_t i = 0; i < depth; ++i) {
debugs(DEBUG_DEFAULT, " ");
}
debugc(DEBUG_DEFAULT, '}');
}
debugc(DEBUG_DEFAULT, '\n');
}
static void debug_stats(void) {
kdebug("--- STATS ---\n");
kdebug("syscalls/s: %lu\n", syscall_count);
if (t_user_init) {
kdebug("init [1] tree:\n");
debug_thread_tree(t_user_init, 0);
}
kdebug("CPU queues:\n");
for (size_t i = 0; i < sched_ncpus; ++i) {
debugf(DEBUG_DEFAULT, " cpu%d [ ", i);
+43
View File
@@ -35,6 +35,7 @@ static int sys_nanosleep(const struct timespec *req, struct timespec *rem);
static int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
static int sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg);
static int sys_access(const char *path, int mode);
static int sys_waitpid(int pid, int *status);
// TODO: const struct termios *termp, const struct winsize *winp
static int sys_openpty(int *master, int *slave);
@@ -102,6 +103,8 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc
return 0;
case SYSCALL_NRX_OPENPTY:
return sys_openpty((int *) rdi, (int *) rsi);
case SYSCALL_NRX_WAITPID:
return sys_waitpid((int) rdi, (int *) rsi);
default:
kerror("unknown syscall: %u\n", rax);
@@ -367,6 +370,7 @@ static void sys_exit(int status) {
struct thread *thr = get_cpu()->thread;
_assert(thr);
kdebug("%u exited with code %d\n", thr->pid, status);
thr->exit_code = status;
thr->flags |= THREAD_STOPPED;
}
@@ -451,3 +455,42 @@ static void sys_sigret(void) {
panic("Fuck\n");
}
static int sys_waitpid(int pid, int *status) {
struct thread *thr = get_cpu()->thread;
_assert(thr);
// Find child with such PID
struct thread *waited = NULL;
int wait_good = 0;
for (struct thread *child = thr->child; child; child = child->next_child) {
if (!(child->flags & THREAD_KERNEL) && (int) child->pid == pid) {
waited = child;
break;
}
}
if (!waited) {
return -ESRCH;
}
while (1) {
if (waited->flags & THREAD_STOPPED) {
kdebug("%d is done waiting for %d\n", thr->pid, waited->pid);
wait_good = 1;
break;
}
asm volatile ("sti; hlt; cli");
}
if (wait_good) {
if (status) {
*status = waited->exit_code;
}
waited->flags |= THREAD_DONE_WAITING;
thread_terminate(waited);
}
return 0;
}
+1
View File
@@ -43,6 +43,7 @@ int main(int argc, char **argv) {
// TODO: first argument is used for the program name itself
if (argc != 1) {
printf("wrong\n");
usleep(1000000);
return -1;
}
+5 -1
View File
@@ -366,6 +366,8 @@ static int cmd_exec(const char *line) {
};
int pid = fork();
int res;
int status;
switch (pid) {
case -1:
@@ -377,7 +379,9 @@ static int cmd_exec(const char *line) {
}
exit(-1);
default:
// TODO: waitpid
if (waitpid(pid, &status) != 0) {
perror("waitpid()");
}
return 0;
}
}
+1
View File
@@ -25,5 +25,6 @@ int openpty(int *amaster, int *aslave);
int gettimeofday(struct timeval *tv, struct timezone *tz);
int reboot(int magic1, int magic2, unsigned int cmd, void *arg);
int access(const char *filename, int mode);
int waitpid(int pid, int *status);
__attribute__((noreturn)) void exit(int code);
+4
View File
@@ -159,6 +159,10 @@ int access(const char *filename, int mode) {
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NR_ACCESS, filename, mode));
}
int waitpid(int pid, int *status) {
return SET_ERRNO(int, ASM_SYSCALL2(SYSCALL_NRX_WAITPID, pid, status));
}
// Although sbrk() is implemented in userspace, I guess it should also be here
void *sbrk(intptr_t inc) {
if (inc == 0) {