ref: 62c66b9e4f72137a9e689c7af406c09fa782bb26
parent: 301ac0c488bf1f0d5fb092f47852a1a3efbc3140
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;
--
⑨