summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2018-12-05 01:43:19 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2018-12-05 01:43:19 +0100
commitd15aca0532d83216e9db9c4107eabaf1fdf21925 (patch)
tree393df6be39912032dcaa6826b4588296d141526b
parent79bfff6437def01409c373f3e053d092d84ad20e (diff)
kernel: fix tprof on multiprocessor
segclock() has to be called from hzclock(), otherwise only processes running on cpu0 would catche the interrupt and the time delta would be wrong. lock the segment when allocating Seg->profile as profile ctl might be issued from multiple processes. Proc->debug qlock is not sufficient. Seg->profile can never be freed or reallocated once set as the timer interrupt accesses it without any locking.
-rw-r--r--sys/src/9/port/devproc.c41
-rw-r--r--sys/src/9/port/portclock.c11
-rw-r--r--sys/src/9/port/portmkfile2
3 files changed, 26 insertions, 28 deletions
diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c
index d54fcb507..bb6d3d970 100644
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -1,6 +1,5 @@
#include "u.h"
#include <trace.h>
-#include "tos.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
@@ -167,22 +166,6 @@ static int topens;
static int tproduced, tconsumed;
void (*proctrace)(Proc*, int, vlong);
-static void
-profclock(Ureg *ur, Timer *)
-{
- Tos *tos;
-
- if(up == nil || up->state != Running)
- return;
-
- /* user profiling clock */
- if(userureg(ur)){
- tos = (Tos*)(USTKTOP-sizeof(Tos));
- tos->clock += TK2MS(1);
- segclock(ur->pc);
- }
-}
-
static int lenwatchpt(Proc *);
static int
@@ -304,7 +287,6 @@ procinit(void)
{
if(conf.nproc >= (1<<(16-QSHIFT))-1)
print("warning: too many procs for devproc\n");
- addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */
}
static Chan*
@@ -1454,7 +1436,8 @@ void
procctlreq(Proc *p, char *va, int n)
{
Segment *s;
- int npc, pri;
+ uintptr npc;
+ int pri;
Cmdbuf *cb;
Cmdtab *ct;
vlong time;
@@ -1520,14 +1503,20 @@ procctlreq(Proc *p, char *va, int n)
break;
case CMprofile:
s = p->seg[TSEG];
- if(s == nil || (s->type&SG_TYPE) != SG_TEXT)
- error(Ebadctl);
- if(s->profile != nil)
- free(s->profile);
+ if(s == nil || (s->type&SG_TYPE) != SG_TEXT) /* won't expand */
+ error(Egreg);
+ eqlock(s);
npc = (s->top-s->base)>>LRESPROF;
- s->profile = malloc(npc*sizeof(*s->profile));
- if(s->profile == nil)
- error(Enomem);
+ if(s->profile == nil){
+ s->profile = malloc(npc*sizeof(*s->profile));
+ if(s->profile == nil){
+ qunlock(s);
+ error(Enomem);
+ }
+ } else {
+ memset(s->profile, 0, npc*sizeof(*s->profile));
+ }
+ qunlock(s);
break;
case CMstart:
if(p->state != Stopped)
diff --git a/sys/src/9/port/portclock.c b/sys/src/9/port/portclock.c
index 47f85f8e1..e2a96f757 100644
--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -5,6 +5,7 @@
#include "fns.h"
#include "io.h"
#include "ureg.h"
+#include "tos.h"
struct Timers
{
@@ -167,8 +168,16 @@ hzclock(Ureg *ur)
if(m->machno == 0)
checkalarms();
- if(up && up->state == Running)
+ if(up && up->state == Running){
+ if(userureg(ur)){
+ /* user profiling clock */
+ Tos *tos = (Tos*)(USTKTOP-sizeof(Tos));
+ tos->clock += TK2MS(1);
+ segclock(ur->pc);
+ }
+
hzsched(); /* in proc.c */
+ }
}
void
diff --git a/sys/src/9/port/portmkfile b/sys/src/9/port/portmkfile
index 3ad8a7b51..af9647f53 100644
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -87,7 +87,7 @@ screen.$O: screen.h /sys/include/draw.h /sys/include/memdraw.h /sys/include/curs
thwack.$O: ../port/thwack.h
unthwack.$O: ../port/thwack.h
devsdp.$O: ../port/thwack.h
-devproc.$O sysproc.$O: /sys/include/tos.h
+portclock.$O sysproc.$O: /sys/include/tos.h
devproc.$O edf.$O proc.$O: /sys/include/trace.h
auth.$O devcons.$O: /sys/include/authsrv.h
devcap.$O: /sys/include/libsec.h