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.