Properly refcnt child processes Parents hold a ref on their children. We didn't incref for this. For forked processes, this was working, since we failed to decref. Spawn, which decreffed properly, blew up. I think the ksched still had a copy of the proc, in this case, and it tried to run it. The kref check (can't incref when 0) caught this.
diff --git a/kern/src/process.c b/kern/src/process.c index dd50f64..e980429 100644 --- a/kern/src/process.c +++ b/kern/src/process.c
@@ -303,6 +303,7 @@ p->exitcode = 1337; /* so we can see processes killed by the kernel */ if (parent) { p->ppid = parent->pid; + proc_incref(p, 1); /* storing a ref in the parent */ /* using the CV's lock to protect anything related to child waiting */ cv_lock(&parent->child_wait); TAILQ_INSERT_TAIL(&parent->children, p, sibling_link); @@ -878,7 +879,7 @@ /* After this, the child won't be able to get more refs to us, but it may * still have some references in running code. */ child->ppid = 0; - proc_decref(child); /* ref that was keeping the child alive after dying */ + proc_decref(child); /* ref that was keeping the child alive on the list */ return 0; }
diff --git a/kern/src/syscall.c b/kern/src/syscall.c index 210537a..4d2de54 100644 --- a/kern/src/syscall.c +++ b/kern/src/syscall.c
@@ -449,6 +449,7 @@ { struct proc *temp; int8_t state = 0; + int ret; // TODO: right now we only support fork for single-core processes if (e->state != PROC_RUNNING_S) { @@ -513,7 +514,9 @@ // when the parent dies, or at least decref it printd("[PID %d] fork PID %d\n", e->pid, env->pid); - return env->pid; + ret = env->pid; + proc_decref(env); /* give up the reference created in proc_alloc() */ + return ret; } /* Load the binary "path" into the current process, and start executing it.