ref: feda4b1ed25f37676b23d3ee35aa44e14257a6b0
parent: f16547d604a8fd723f81dc145b4f42532a7fbdc5
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Jan 3 23:45:56 EST 2024
kernel: add extra "New" process state to catch invalid state transitions For ready() to check invalid state transitions, we want to ensure that ready() is never called on a dead proc (or one that is currently dying), however when we create a new process, its initial state was "Dead" until is is ready()d. Instead, introduce the state "New", which is set when the proc is removed from the freelist by newproc(), making New -> Ready -> Running state transition valid. Also make sure we never leave notes to deadly processes or ones that are in "Broken" state.
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -1296,7 +1296,7 @@
qunlock(&p->seglock);
nexterror();
}
- if(p->state == Dead || p->pid != PID(c->qid))
+ if(p->state <= New || p->pid != PID(c->qid))
error(Eprocdied);
if((s = p->seg[TSEG]) == nil)
error(Enonexist);
@@ -1647,7 +1647,7 @@
qunlock(&p->seglock);
nexterror();
}
- if(p->state == Dead || p->pid != PID(c->qid))
+ if(p->state <= New || p->pid != PID(c->qid))
error(Eprocdied);
for(i = 0; i < NSEG; i++) {
--- a/sys/src/9/port/edf.c
+++ b/sys/src/9/port/edf.c
@@ -372,7 +372,7 @@
/* Look for another proc with the same period to synchronize to */
for(i=0; (r = proctab(i)) != nil; i++) {
- if(r->state == Dead || r == p)
+ if(r->state <= New || r == p)
continue;
if(r->edf == nil || (r->edf->flags & Admitted) == 0)
continue;
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -607,6 +607,7 @@
{
Dead = 0, /* Process states */
Moribund,
+ New,
Ready,
Scheding,
Running,
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -42,6 +42,7 @@
{ /* BUG: generate automatically */
"Dead",
"Moribund",
+ "New",
"Ready",
"Scheding",
"Running",
@@ -80,6 +81,7 @@
ready(up);
break;
case Moribund:
+ mmurelease(up);
up->state = Dead;
edfstop(up);
if(up->edf != nil){
@@ -86,9 +88,6 @@
free(up->edf);
up->edf = nil;
}
-
- mmurelease(up);
-
lock(&procalloc);
up->mach = nil;
up->qnext = procalloc.free;
@@ -456,9 +455,21 @@
Schedq *rq;
void (*pt)(Proc*, int, vlong);
- if(p->state == Ready){
- print("double ready %s %lud pc %p\n", p->text, p->pid, getcallerpc(&p));
+ switch(p->state){
+ case Running:
+ if(p == up)
+ break;
+ /* wet floor */
+ case Dead:
+ case Moribund:
+ case Scheding:
+ print("ready %s %s %lud pc %p\n", statename[p->state],
+ p->text, p->pid, getcallerpc(&p));
return;
+ case Ready:
+ print("double ready %s %lud pc %p\n",
+ p->text, p->pid, getcallerpc(&p));
+ return;
}
s = splhi();
@@ -649,11 +660,13 @@
p->index = procalloc.nextindex++;
procalloc.tab[p->index] = p;
}
+ assert(p->state == Dead);
procalloc.free = p->qnext;
p->qnext = nil;
unlock(&procalloc);
- p->psstate = "New";
+ p->psstate = nil;
+ p->state = New;
p->fpstate = FPinit;
#ifdef KFPSTATE
p->kfpstate = FPinit;
@@ -930,7 +943,8 @@
/* try for the second lock */
if(canlock(r)){
if(p->state != Wakeme || r->p != p)
- panic("procinterrupt: state %d %d %d", r->p != p, p->r != r, p->state);
+ panic("procinterrupt: state %d %d %d",
+ r->p != p, p->r != r, p->state);
p->r = nil;
r->p = nil;
ready(p);
@@ -1022,6 +1036,7 @@
if(u != nil && up->lastnote->ref == 1 && strncmp(up->lastnote->msg, "sys:", 4) == 0){
int l = strlen(up->lastnote->msg);
assert(l < ERRMAX);
+ assert(userureg(u));
snprint(up->lastnote->msg+l, ERRMAX-l, " pc=%#p", u->pc);
}
@@ -1051,7 +1066,7 @@
int
pushnote(Proc *p, Note *n)
{
- if(p->pid == 0){
+ if(p->state <= New || p->state == Broken || p->pid == 0){
freenote(n);
return 0;
}
@@ -1095,12 +1110,10 @@
n = mknote(msg, flag);
for(i = 0; (p = proctab(i)) != nil; i++){
- if(p == up)
+ if(p == up || p->noteid != noteid || p->kp)
continue;
- if(p->noteid != noteid || p->kp)
- continue;
qlock(&p->debug);
- if(p->noteid == noteid){
+ if(p->noteid == noteid && !p->kp){
incref(n);
pushnote(p, n);
}
@@ -1424,7 +1437,7 @@
memset(await, 0, conf.nmach*sizeof(await[0]));
nwait = 0;
for(i = 0; (p = proctab(i)) != nil; i++){
- if(p->state != Dead && (*match)(p, a)){
+ if(p->state > New && (*match)(p, a)){
p->newtlb = 1;
for(nm = 0; nm < conf.nmach; nm++){
if(MACHP(nm)->proc == p){
@@ -1574,7 +1587,6 @@
procpriority(p, PriKproc, 0);
- p->psstate = nil;
ready(p);
}
@@ -1606,7 +1618,7 @@
case Proc_stopme:
up->procctl = 0;
state = up->psstate;
- up->psstate = "Stopped";
+ up->psstate = statename[Stopped];
/* free a waiting debugger */
s = spllo();
qlock(&up->debug);
@@ -1691,7 +1703,7 @@
max = 0;
kp = nil;
for(i = 0; (p = proctab(i)) != nil; i++) {
- if(p->state == Dead || p->kp || p->parentpid == 0)
+ if(p->state <= New || p->kp || p->parentpid == 0)
continue;
if((p->noswap || (p->procmode & 0222) == 0) && strcmp(eve, p->user) == 0)
continue;
@@ -1706,7 +1718,7 @@
print("%lud: %s killed: %s\n", kp->pid, kp->text, why);
qlock(&kp->seglock);
for(i = 0; (p = proctab(i)) != nil; i++) {
- if(p->state == Dead || p->kp)
+ if(p->state <= New || p->kp)
continue;
if(p != kp && p->seg[BSEG] != nil && p->seg[BSEG] == kp->seg[BSEG])
p->procctl = Proc_exitbig;