summaryrefslogtreecommitdiff
path: root/sys/src/9/port/alarm.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-01-01 05:14:38 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2014-01-01 05:14:38 +0100
commitf481ac716d3fd3320ddf0672b395cf374a41a1dd (patch)
treec2f8e088a075dcf616b781bce570cba27a3adb5a /sys/src/9/port/alarm.c
parent0feb6e06af1e48c2b1a937c6a593fceeafd728d2 (diff)
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.
Diffstat (limited to 'sys/src/9/port/alarm.c')
-rw-r--r--sys/src/9/port/alarm.c45
1 files changed, 23 insertions, 22 deletions
diff --git a/sys/src/9/port/alarm.c b/sys/src/9/port/alarm.c
index b78088665..8fb45be94 100644
--- a/sys/src/9/port/alarm.c
+++ b/sys/src/9/port/alarm.c
@@ -11,7 +11,7 @@ void
alarmkproc(void*)
{
Proc *rp;
- ulong now;
+ ulong now, when;
while(waserror())
;
@@ -19,20 +19,20 @@ alarmkproc(void*)
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 @@ void
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 @@ procalarm(ulong time)
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;