kernel: fix twakeup()/timerdel() race condition
timerdel() did not make sure that the timer function is not active (on another cpu). just acquiering the Timer lock in the timer function only blocks the caller of timerdel()/timeradd() but not the other way arround (on a multiprocessor). this changes the timer code to track activity of the timer function, having timerdel() wait until the timer has finished executing.
This commit is contained in:
parent
bfae9e08be
commit
0c1110ace2
|
@ -207,7 +207,7 @@ release(Proc *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
releaseintr(Ureg*, Timer *t)
|
releaseintr(Ureg *u, Timer *t)
|
||||||
{
|
{
|
||||||
Proc *p;
|
Proc *p;
|
||||||
extern int panicking;
|
extern int panicking;
|
||||||
|
@ -254,9 +254,7 @@ releaseintr(Ureg*, Timer *t)
|
||||||
case Wakeme:
|
case Wakeme:
|
||||||
release(p);
|
release(p);
|
||||||
edfunlock();
|
edfunlock();
|
||||||
if(p->trend)
|
twakeup(u, t);
|
||||||
wakeup(p->trend);
|
|
||||||
p->trend = nil;
|
|
||||||
if(up){
|
if(up){
|
||||||
up->delaysched++;
|
up->delaysched++;
|
||||||
delayedscheds++;
|
delayedscheds++;
|
||||||
|
@ -445,8 +443,7 @@ edfstop(Proc *p)
|
||||||
if(p->trace && (pt = proctrace))
|
if(p->trace && (pt = proctrace))
|
||||||
pt(p, SExpel, 0);
|
pt(p, SExpel, 0);
|
||||||
e->flags &= ~Admitted;
|
e->flags &= ~Admitted;
|
||||||
if(e->tt)
|
timerdel(e);
|
||||||
timerdel(e);
|
|
||||||
edfunlock();
|
edfunlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,20 +476,23 @@ edfyield(void)
|
||||||
e->r = e->t;
|
e->r = e->t;
|
||||||
e->flags |= Yield;
|
e->flags |= Yield;
|
||||||
e->d = now;
|
e->d = now;
|
||||||
if (up->tt == nil){
|
n = e->t - now;
|
||||||
n = e->t - now;
|
if(n < 20)
|
||||||
if(n < 20)
|
n = 20;
|
||||||
n = 20;
|
up->tns = 1000LL * n;
|
||||||
up->tns = 1000LL * n;
|
up->tf = releaseintr;
|
||||||
up->tf = releaseintr;
|
up->tmode = Trelative;
|
||||||
up->tmode = Trelative;
|
up->ta = up;
|
||||||
up->ta = up;
|
up->trend = &up->sleep;
|
||||||
up->trend = &up->sleep;
|
timeradd(up);
|
||||||
timeradd(up);
|
|
||||||
}else if(up->tf != releaseintr)
|
|
||||||
print("edfyield: surprise! %#p\n", up->tf);
|
|
||||||
edfunlock();
|
edfunlock();
|
||||||
|
if(waserror()){
|
||||||
|
up->trend = nil;
|
||||||
|
timerdel(up);
|
||||||
|
nexterror();
|
||||||
|
}
|
||||||
sleep(&up->sleep, yfn, nil);
|
sleep(&up->sleep, yfn, nil);
|
||||||
|
poperror();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -112,9 +112,13 @@ timeradd(Timer *nt)
|
||||||
void
|
void
|
||||||
timerdel(Timer *dt)
|
timerdel(Timer *dt)
|
||||||
{
|
{
|
||||||
|
Mach *mp;
|
||||||
Timers *tt;
|
Timers *tt;
|
||||||
uvlong when;
|
uvlong when;
|
||||||
|
|
||||||
|
/* avoid Tperiodic getting re-added */
|
||||||
|
dt->tmode = Trelative;
|
||||||
|
|
||||||
ilock(dt);
|
ilock(dt);
|
||||||
if(tt = dt->tt){
|
if(tt = dt->tt){
|
||||||
ilock(tt);
|
ilock(tt);
|
||||||
|
@ -123,7 +127,16 @@ timerdel(Timer *dt)
|
||||||
timerset(tt->head->twhen);
|
timerset(tt->head->twhen);
|
||||||
iunlock(tt);
|
iunlock(tt);
|
||||||
}
|
}
|
||||||
|
if((mp = dt->tactive) == nil || mp->machno == m->machno){
|
||||||
|
iunlock(dt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
iunlock(dt);
|
iunlock(dt);
|
||||||
|
|
||||||
|
/* rare, but tf can still be active on another cpu */
|
||||||
|
while(dt->tactive == mp && dt->tt == nil)
|
||||||
|
if(up->nlocks == 0 && islo())
|
||||||
|
sched();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -190,12 +203,14 @@ timerintr(Ureg *u, Tval)
|
||||||
tt->head = t->tnext;
|
tt->head = t->tnext;
|
||||||
assert(t->tt == tt);
|
assert(t->tt == tt);
|
||||||
t->tt = nil;
|
t->tt = nil;
|
||||||
|
t->tactive = MACHP(m->machno);
|
||||||
fcallcount[m->machno]++;
|
fcallcount[m->machno]++;
|
||||||
iunlock(tt);
|
iunlock(tt);
|
||||||
if(t->tf)
|
if(t->tf)
|
||||||
(*t->tf)(u, t);
|
(*t->tf)(u, t);
|
||||||
else
|
else
|
||||||
callhzclock++;
|
callhzclock++;
|
||||||
|
t->tactive = nil;
|
||||||
ilock(tt);
|
ilock(tt);
|
||||||
if(t->tmode == Tperiodic)
|
if(t->tmode == Tperiodic)
|
||||||
tadd(tt, t);
|
tadd(tt, t);
|
||||||
|
|
|
@ -556,6 +556,7 @@ struct Timer
|
||||||
void *ta;
|
void *ta;
|
||||||
/* Internal */
|
/* Internal */
|
||||||
Lock;
|
Lock;
|
||||||
|
Mach *tactive; /* The cpu that tf is active on */
|
||||||
Timers *tt; /* Timers queue this timer runs on */
|
Timers *tt; /* Timers queue this timer runs on */
|
||||||
Tval tticks; /* tns converted to ticks */
|
Tval tticks; /* tns converted to ticks */
|
||||||
Tval twhen; /* ns represented in fastticks */
|
Tval twhen; /* ns represented in fastticks */
|
||||||
|
|
|
@ -348,6 +348,7 @@ void todinit(void);
|
||||||
void todset(vlong, vlong, int);
|
void todset(vlong, vlong, int);
|
||||||
Block* trimblock(Block*, int, int);
|
Block* trimblock(Block*, int, int);
|
||||||
void tsleep(Rendez*, int (*)(void*), void*, ulong);
|
void tsleep(Rendez*, int (*)(void*), void*, ulong);
|
||||||
|
void twakeup(Ureg*, Timer *);
|
||||||
int uartctl(Uart*, char*);
|
int uartctl(Uart*, char*);
|
||||||
int uartgetc(void);
|
int uartgetc(void);
|
||||||
void uartkick(void*);
|
void uartkick(void*);
|
||||||
|
|
|
@ -822,28 +822,17 @@ tfn(void *arg)
|
||||||
return up->trend == nil || up->tfn(arg);
|
return up->trend == nil || up->tfn(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
twakeup(Ureg*, Timer *t)
|
twakeup(Ureg*, Timer *t)
|
||||||
{
|
{
|
||||||
Proc *p;
|
Proc *p;
|
||||||
Rendez *trend;
|
Rendez *trend;
|
||||||
|
|
||||||
ilock(t);
|
|
||||||
p = t->ta;
|
p = t->ta;
|
||||||
trend = p->trend;
|
trend = p->trend;
|
||||||
if(trend != nil){
|
if(trend != nil){
|
||||||
wakeup(trend);
|
|
||||||
p->trend = nil;
|
p->trend = nil;
|
||||||
}
|
wakeup(trend);
|
||||||
iunlock(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
stoptimer(void)
|
|
||||||
{
|
|
||||||
if(up->trend != nil){
|
|
||||||
up->trend = nil;
|
|
||||||
timerdel(up);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,11 +853,13 @@ tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
|
||||||
timeradd(up);
|
timeradd(up);
|
||||||
|
|
||||||
if(waserror()){
|
if(waserror()){
|
||||||
stoptimer();
|
up->trend = nil;
|
||||||
|
timerdel(up);
|
||||||
nexterror();
|
nexterror();
|
||||||
}
|
}
|
||||||
sleep(r, tfn, arg);
|
sleep(r, tfn, arg);
|
||||||
stoptimer();
|
up->trend = nil;
|
||||||
|
timerdel(up);
|
||||||
poperror();
|
poperror();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,8 +1093,7 @@ pexit(char *exitstr, int freemem)
|
||||||
void (*pt)(Proc*, int, vlong);
|
void (*pt)(Proc*, int, vlong);
|
||||||
|
|
||||||
up->alarm = 0;
|
up->alarm = 0;
|
||||||
if(up->tt != nil)
|
timerdel(up);
|
||||||
timerdel(up);
|
|
||||||
pt = proctrace;
|
pt = proctrace;
|
||||||
if(pt != nil)
|
if(pt != nil)
|
||||||
pt(up, SDead, 0);
|
pt(up, SDead, 0);
|
||||||
|
|
Loading…
Reference in a new issue