summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2024-01-04 04:45:56 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2024-01-04 04:45:56 +0000
commitfeda4b1ed25f37676b23d3ee35aa44e14257a6b0 (patch)
tree4da41ffe0cfd3a1253878296be13e65a13eebd0f
parentf16547d604a8fd723f81dc145b4f42532a7fbdc5 (diff)
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.
-rw-r--r--sys/src/9/port/devproc.c4
-rw-r--r--sys/src/9/port/edf.c2
-rw-r--r--sys/src/9/port/portdat.h1
-rw-r--r--sys/src/9/port/proc.c46
4 files changed, 33 insertions, 20 deletions
diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c
index 75863291d..8bc1a530b 100644
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -1296,7 +1296,7 @@ proctext(Chan *c, Proc *p)
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 @@ procctlmemio(Chan *c, Proc *p, uintptr offset, void *a, long n, int read)
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++) {
diff --git a/sys/src/9/port/edf.c b/sys/src/9/port/edf.c
index c8c5410c2..33ed501d2 100644
--- a/sys/src/9/port/edf.c
+++ b/sys/src/9/port/edf.c
@@ -372,7 +372,7 @@ edfadmit(Proc *p)
/* 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;
diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h
index 306b465d7..ca4387d03 100644
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -607,6 +607,7 @@ enum
{
Dead = 0, /* Process states */
Moribund,
+ New,
Ready,
Scheding,
Running,
diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c
index d082a40da..2d3e48300 100644
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -42,6 +42,7 @@ char *statename[] =
{ /* BUG: generate automatically */
"Dead",
"Moribund",
+ "New",
"Ready",
"Scheding",
"Running",
@@ -80,15 +81,13 @@ schedinit(void) /* never returns */
ready(up);
break;
case Moribund:
+ mmurelease(up);
up->state = Dead;
edfstop(up);
if(up->edf != nil){
free(up->edf);
up->edf = nil;
}
-
- mmurelease(up);
-
lock(&procalloc);
up->mach = nil;
up->qnext = procalloc.free;
@@ -456,8 +455,20 @@ ready(Proc *p)
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;
}
@@ -649,11 +660,13 @@ newproc(void)
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 @@ procinterrupt(Proc *p)
/* 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 @@ popnote(Ureg *u)
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 @@ mknote(char *msg, int flag)
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 @@ postnotepg(ulong noteid, char *msg, int flag)
n = mknote(msg, flag);
for(i = 0; (p = proctab(i)) != nil; i++){
- if(p == up)
- continue;
- if(p->noteid != noteid || p->kp)
+ if(p == up || 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 @@ procflushmmu(int (*match)(Proc*, void*), void *a)
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 @@ kproc(char *name, void (*func)(void *), void *arg)
procpriority(p, PriKproc, 0);
- p->psstate = nil;
ready(p);
}
@@ -1606,7 +1618,7 @@ procctl(void)
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 @@ killbig(char *why)
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 @@ killbig(char *why)
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;