void procctlreq(Proc*, char*, int);
int procctlmemio(Proc*, uintptr, int, void*, int);
Chan* proctext(Chan*, Proc*);
-Segment* txt2data(Proc*, Segment*);
int procstopped(void*);
void mntscan(Mntwalk*, Proc*);
+ulong procpagecount(Proc *);
static Traceevent *tevents;
static Lock tlock;
readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
}
- l = 0;
- eqlock(&p->seglock);
- if(waserror()){
- qunlock(&p->seglock);
- nexterror();
- }
- for(i=0; i<NSEG; i++){
- if(s = p->seg[i]){
- eqlock(s);
- l += mcountseg(s);
- qunlock(s);
- }
- }
- poperror();
- qunlock(&p->seglock);
-
- readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l*BY2PG/1024, NUMSIZE);
+ readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
memmove(a, statbuf+offset, n);
return p->state == Stopped;
}
+ulong
+procpagecount(Proc *p)
+{
+ Segment *s;
+ ulong pages;
+ int i;
+
+ eqlock(&p->seglock);
+ if(waserror()){
+ qunlock(&p->seglock);
+ nexterror();
+ }
+ pages = 0;
+ for(i=0; i<NSEG; i++){
+ if((s = p->seg[i]) != nil){
+ eqlock(s);
+ pages += mcountseg(s);
+ qunlock(s);
+ }
+ }
+ qunlock(&p->seglock);
+ poperror();
+
+ return pages;
+}
+
int
procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
{
Pte *pte;
Page *pg;
Segment *s;
- uintptr soff, l;
- char *a = va, *b;
+ uintptr soff;
+ char *a, *b;
+ int i, l;
+
+ /* Only one page at a time */
+ l = BY2PG - (offset&(BY2PG-1));
+ if(n > l)
+ n = l;
+
+ /*
+ * Make temporary copy to avoid fault while we have
+ * segment locked as we would deadlock when trying
+ * to read the calling procs memory.
+ */
+ a = malloc(n);
+ if(a == nil)
+ error(Enomem);
+ if(waserror()) {
+ free(a);
+ nexterror();
+ }
+
+ if(!read)
+ memmove(a, va, n); /* can fault */
for(;;) {
- s = seg(p, offset, 1);
- if(s == 0)
+ s = seg(p, offset, 0);
+ if(s == nil)
error(Ebadarg);
- if(offset+n >= s->top)
- n = s->top-offset;
+ eqlock(&p->seglock);
+ if(waserror()) {
+ qunlock(&p->seglock);
+ nexterror();
+ }
- if(!read && (s->type&SG_TYPE) == SG_TEXT)
- s = txt2data(p, s);
+ for(i = 0; i < NSEG; i++) {
+ if(p->seg[i] == s)
+ break;
+ }
+ if(i == NSEG)
+ error(Egreg); /* segment gone */
- s->steal++;
- soff = offset-s->base;
- if(waserror()) {
- s->steal--;
+ eqlock(s);
+ if(waserror()){
+ qunlock(s);
nexterror();
}
- if(fixfault(s, offset, read, 0) == 0)
- break;
+ if(!read && (s->type&SG_TYPE) == SG_TEXT) {
+ s = txt2data(s);
+ p->seg[i] = s;
+ }
+ incref(s);
+ qunlock(&p->seglock);
+ poperror();
poperror();
- s->steal--;
+ /* segment s still locked, fixfault() unlocks */
+ if(!waserror()){
+ if(fixfault(s, offset, read, 0) == 0)
+ break;
+ poperror();
+ }
+ putseg(s);
}
- poperror();
+
+ /*
+ * Only access the page while segment is locked
+ * as the proc could segfree or relocate the pte
+ * concurrently.
+ */
+ eqlock(s);
+ if(waserror()){
+ qunlock(s);
+ nexterror();
+ }
+ if(offset+n >= s->top)
+ n = s->top-offset;
+ soff = offset-s->base;
pte = s->map[soff/PTEMAPMEM];
- if(pte == 0)
- panic("procctlmemio");
+ if(pte == nil)
+ error(Egreg); /* page gone, should retry? */
pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
if(pagedout(pg))
- panic("procctlmemio1");
-
- l = BY2PG - (offset&(BY2PG-1));
- if(n > l)
- n = l;
+ error(Egreg); /* page gone, should retry? */
+ /* Map and copy the page */
k = kmap(pg);
- if(waserror()) {
- s->steal--;
- kunmap(k);
- nexterror();
- }
b = (char*)VA(k);
b += offset&(BY2PG-1);
- if(read == 1)
- memmove(a, b, n); /* This can fault */
+ if(read)
+ memmove(a, b, n);
else
memmove(b, a, n);
kunmap(k);
- poperror();
/* Ensure the process sees text page changes */
if(s->flushme)
memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
- s->steal--;
-
- if(read == 0)
+ if(!read)
p->newtlb = 1;
- return n;
-}
-
-Segment*
-txt2data(Proc *p, Segment *s)
-{
- int i;
- Segment *ps;
-
- ps = newseg(SG_DATA, s->base, s->size);
- ps->image = s->image;
- incref(ps->image);
- ps->fstart = s->fstart;
- ps->flen = s->flen;
- ps->flushme = 1;
-
- qlock(&p->seglock);
- for(i = 0; i < NSEG; i++)
- if(p->seg[i] == s)
- break;
- if(i == NSEG)
- panic("segment gone");
-
qunlock(s);
+ poperror();
putseg(s);
- qlock(ps);
- p->seg[i] = ps;
- qunlock(&p->seglock);
-
- return ps;
-}
+ poperror();
-Segment*
-data2txt(Segment *s)
-{
- Segment *ps;
+ if(read)
+ memmove(va, a, n); /* can fault */
- ps = newseg(SG_TEXT, s->base, s->size);
- ps->image = s->image;
- incref(ps->image);
- ps->fstart = s->fstart;
- ps->flen = s->flen;
- ps->flushme = 1;
+ free(a);
+ poperror();
- return ps;
+ return n;
}