summaryrefslogtreecommitdiff
path: root/sys/src/9/port/proc.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2017-03-29 00:30:53 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2017-03-29 00:30:53 +0200
commit0c1110ace2f247d2605599bb02f2866aee2ab1c6 (patch)
tree9b70a5d254b5289532e9017a9a00180eaea413d1 /sys/src/9/port/proc.c
parentbfae9e08be692b944ab3018d98693a15ca38a64c (diff)
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.
Diffstat (limited to 'sys/src/9/port/proc.c')
-rw-r--r--sys/src/9/port/proc.c24
1 files changed, 7 insertions, 17 deletions
diff --git a/sys/src/9/port/proc.c b/sys/src/9/port/proc.c
index b39fc0942..e9a299c20 100644
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -822,28 +822,17 @@ tfn(void *arg)
return up->trend == nil || up->tfn(arg);
}
-static void
+void
twakeup(Ureg*, Timer *t)
{
Proc *p;
Rendez *trend;
- ilock(t);
p = t->ta;
trend = p->trend;
if(trend != nil){
- wakeup(trend);
p->trend = nil;
- }
- iunlock(t);
-}
-
-static void
-stoptimer(void)
-{
- if(up->trend != nil){
- up->trend = nil;
- timerdel(up);
+ wakeup(trend);
}
}
@@ -864,11 +853,13 @@ tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
timeradd(up);
if(waserror()){
- stoptimer();
+ up->trend = nil;
+ timerdel(up);
nexterror();
}
sleep(r, tfn, arg);
- stoptimer();
+ up->trend = nil;
+ timerdel(up);
poperror();
}
@@ -1102,8 +1093,7 @@ pexit(char *exitstr, int freemem)
void (*pt)(Proc*, int, vlong);
up->alarm = 0;
- if(up->tt != nil)
- timerdel(up);
+ timerdel(up);
pt = proctrace;
if(pt != nil)
pt(up, SDead, 0);