diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index b7ec23a7..45d58cec 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -46,10 +46,12 @@ typedef struct thread_t { spinlock_t sleeplock; int wakeupreason; bool shouldexit; + void *kernelarg; } thread_t; typedef struct proc_t { spinlock_t lock; + int refcount; int status; int state; struct proc_t *sibling; @@ -77,6 +79,13 @@ typedef struct proc_t { #include #define UMASK(mode) ((mode) & ~_cpu()->thread->proc->umask) +#define PROC_HOLD(v) __atomic_add_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) +#define PROC_RELEASE(v) {\ + if (__atomic_sub_fetch(&(v)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\ + sched_inactiveproc(v); \ + (v) = NULL; \ + } \ + } extern proc_t *sched_initproc; @@ -101,5 +110,6 @@ void sched_destroythread(thread_t *); void sched_targetcpu(struct cpu_t *cpu); void sched_sleepus(size_t us); void sched_apentry(); +void sched_inactiveproc(proc_t *proc); #endif diff --git a/kernel-src/sys/scheduler.c b/kernel-src/sys/scheduler.c index 786e1f96..7a536163 100644 --- a/kernel-src/sys/scheduler.c +++ b/kernel-src/sys/scheduler.c @@ -51,6 +51,7 @@ proc_t *sched_newproc() { SPINLOCK_INIT(proc->lock); SPINLOCK_INIT(proc->nodeslock); proc->fdcount = 3; + proc->refcount = 1; proc->fdfirst = 3; SPINLOCK_INIT(proc->fdlock); SEMAPHORE_INIT(&proc->waitsem, 0); @@ -87,8 +88,11 @@ thread_t *sched_newthread(void *ip, size_t kstacksize, int priority, proc_t *pro thread->vmmctx = proc ? NULL : &vmm_kernelctx; thread->proc = proc; thread->priority = priority; - if (proc) + if (proc) { + // each thread holds one reference to proc + PROC_HOLD(proc); thread->tid = __atomic_fetch_add(&currpid, 1, __ATOMIC_SEQ_CST); + } CTX_INIT(&thread->context, proc != NULL, true); @@ -229,9 +233,15 @@ __attribute__((noreturn)) void sched_stopcurrentthread() { switchthread(next); } +// called when all threads in a process have exited void sched_procexit() { proc_t *proc = _cpu()->thread->proc; + // the process is going to be referenced by the child list, hold it + // it only holds it now because it has to have running threads to be in the list + // which hold a reference. it won't now since its a zombie, which is why it will be held + PROC_HOLD(proc); + // close fds for (int fd = 0; fd < proc->fdcount; ++fd) fd_close(fd); @@ -245,6 +255,7 @@ void sched_procexit() { proc->state = SCHED_PROC_STATE_ZOMBIE; proc_t *lastchild = proc->child; + spinlock_acquire(&sched_initproc->lock); bool haszombie = false; @@ -270,6 +281,14 @@ void sched_procexit() { semaphore_signal(&sched_initproc->waitsem); } +void sched_inactiveproc(proc_t *proc) { + // proc refcount 0, we can free the structure + // TODO remove from the pid list + + printf("destroying proc!\n"); + sched_destroyproc(proc); +} + static void threadexit_internal(context_t *) { thread_t *thread = _cpu()->thread; // we don't need to access the current thread anymore, as any state will be ignored and we are running on the scheduler stack @@ -301,6 +320,7 @@ __attribute__((noreturn)) void sched_threadexit() { sched_procexit(); vmm_destroycontext(oldctx); + PROC_RELEASE(proc); } } @@ -628,8 +648,11 @@ void sched_runinit() { thread_t *uthread = sched_newthread(entry, PAGE_SIZE * 16, 1, proc, stack); __assert(uthread); + uthread->vmmctx = vmmctx; sched_queue(uthread); VOP_RELEASE(initnode); + // proc starts with 1 refcount, release it here as to only have the thread reference + PROC_RELEASE(proc); } diff --git a/kernel-src/sys/syscalls/fork.c b/kernel-src/sys/syscalls/fork.c index 90539b4d..12c384ad 100644 --- a/kernel-src/sys/syscalls/fork.c +++ b/kernel-src/sys/syscalls/fork.c @@ -57,6 +57,8 @@ syscallret_t syscall_fork(context_t *ctx) { ret.ret = nproc->pid; sched_queue(nthread); + // proc starts with 1 refcount, release it here as to only have the thread reference + PROC_RELEASE(nproc); cleanup: return ret; diff --git a/kernel-src/sys/syscalls/waitpid.c b/kernel-src/sys/syscalls/waitpid.c index 4fe1bbee..7eb0df81 100644 --- a/kernel-src/sys/syscalls/waitpid.c +++ b/kernel-src/sys/syscalls/waitpid.c @@ -75,6 +75,7 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt ret.errno = 0; __assert(iterator); - sched_destroyproc(iterator); + // process will no longer be referenced by the child list + PROC_RELEASE(iterator); return ret; }