ref: 3975f1a956bf1270803893de6e7a2e308c53a89a
parent: 8c1eda734d9bc29e8e2c286f7547c793e5438c3b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Jan 1 00:14:38 EST 2014
kernel: fix alarm postnote race when alarmkproc is commited to send the alarm note to the process, the process might have exited already, or worse, being reused for another process. pexit() zeros p->alarm at the beginning, but the kalarmproc() might read p->alarm before pexit() zeroed it, decide to send the note, then get preempted and pexit() releases the proc. once kalarmproc() is resumed, the proc might be already something different and we send the note to the wrong thing. we now check p->alarm under the debug qlock. that way, pexit() cannot make progress while we test the condition. remove the error label arround postnote(). postnote does not raise error.
--- a/sys/src/9/port/alarm.c
+++ b/sys/src/9/port/alarm.c
@@ -11,7 +11,7 @@
alarmkproc(void*)
{Proc *rp;
- ulong now;
+ ulong now, when;
while(waserror())
;
@@ -19,20 +19,20 @@
for(;;){now = MACHP(0)->ticks;
qlock(&alarms);
- while((rp = alarms.head) && (long)(now - rp->alarm) >= 0){- if(rp->alarm != 0L){- if(canqlock(&rp->debug)){- if(!waserror()){- postnote(rp, 0, "alarm", NUser);
- poperror();
- }
- qunlock(&rp->debug);
- rp->alarm = 0L;
- }else
- break;
+ for(rp = alarms.head; rp != nil; rp = rp->palarm){+ if((when = rp->alarm) == 0)
+ continue;
+ if((long)(now - when) < 0)
+ break;
+ if(!canqlock(&rp->debug))
+ break;
+ if(rp->alarm != 0){+ postnote(rp, 0, "alarm", NUser);
+ rp->alarm = 0;
}
- alarms.head = rp->palarm;
+ qunlock(&rp->debug);
}
+ alarms.head = rp;
qunlock(&alarms);
sleep(&alarmr, return0, 0);
@@ -46,13 +46,15 @@
checkalarms(void)
{Proc *p;
- ulong now;
+ ulong now, when;
p = alarms.head;
- now = MACHP(0)->ticks;
-
- if(p != nil && (long)(now - p->alarm) >= 0)
- wakeup(&alarmr);
+ if(p != nil){+ now = MACHP(0)->ticks;
+ when = p->alarm;
+ if(when == 0 || (long)(now - when) >= 0)
+ wakeup(&alarmr);
+ }
}
ulong
@@ -61,10 +63,9 @@
Proc **l, *f;
ulong when, old;
- if(up->alarm)
- old = tk2ms(up->alarm - MACHP(0)->ticks);
- else
- old = 0;
+ old = up->alarm;
+ if(old)
+ old = tk2ms(old - MACHP(0)->ticks);
if(time == 0) {up->alarm = 0;
return old;
--
⑨