segment.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       segment.c (14276B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 static void        imagereclaim(void);
            9 static void        imagechanreclaim(void);
           10 
           11 #include "io.h"
           12 
           13 /*
           14  * Attachable segment types
           15  */
           16 static Physseg physseg[10] = {
           17         { SG_SHARED,        "shared",        0,        SEGMAXSIZE,        0,         0 },
           18         { SG_BSS,        "memory",        0,        SEGMAXSIZE,        0,        0 },
           19         { 0,                0,                0,        0,                0,        0 },
           20 };
           21 
           22 static Lock physseglock;
           23 
           24 #define NFREECHAN        64
           25 #define IHASHSIZE        64
           26 #define ihash(s)        imagealloc.hash[s%IHASHSIZE]
           27 static struct Imagealloc
           28 {
           29         Lock lk;
           30         Image        *free;
           31         Image        *hash[IHASHSIZE];
           32         QLock        ireclaim;        /* mutex on reclaiming free images */
           33 
           34         Chan        **freechan;        /* free image channels */
           35         int        nfreechan;        /* number of free channels */
           36         int        szfreechan;        /* size of freechan array */
           37         QLock        fcreclaim;        /* mutex on reclaiming free channels */
           38 }imagealloc;
           39 
           40 Segment* (*_globalsegattach)(Proc*, char*);
           41 
           42 void
           43 initseg(void)
           44 {
           45         Image *i, *ie;
           46 
           47         imagealloc.free = xalloc(conf.nimage*sizeof(Image));
           48         if (imagealloc.free == nil)
           49                 panic("initseg: no memory");
           50         ie = &imagealloc.free[conf.nimage-1];
           51         for(i = imagealloc.free; i < ie; i++)
           52                 i->next = i+1;
           53         i->next = 0;
           54         imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
           55         imagealloc.szfreechan = NFREECHAN;
           56 }
           57 
           58 Segment *
           59 newseg(int type, ulong base, ulong size)
           60 {
           61         Segment *s;
           62         int mapsize;
           63 
           64         if(size > (SEGMAPSIZE*PTEPERTAB))
           65                 error(Enovmem);
           66 
           67         if(swapfull())
           68                 error(Enoswap);
           69         s = smalloc(sizeof(Segment));
           70         s->ref.ref = 1;
           71         s->type = type;
           72         s->base = base;
           73         s->top = base+(size*BY2PG);
           74         s->size = size;
           75         s->sema.prev = &s->sema;
           76         s->sema.next = &s->sema;
           77 
           78         mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
           79         if(mapsize > nelem(s->ssegmap)){
           80                 mapsize *= 2;
           81                 if(mapsize > (SEGMAPSIZE*PTEPERTAB))
           82                         mapsize = (SEGMAPSIZE*PTEPERTAB);
           83                 s->map = smalloc(mapsize*sizeof(Pte*));
           84                 s->mapsize = mapsize;
           85         }
           86         else{
           87                 s->map = s->ssegmap;
           88                 s->mapsize = nelem(s->ssegmap);
           89         }
           90 
           91         return s;
           92 }
           93 
           94 void
           95 putseg(Segment *s)
           96 {
           97         Pte **pp, **emap;
           98         Image *i;
           99 
          100         if(s == 0)
          101                 return;
          102 
          103         i = s->image;
          104         if(i != 0) {
          105                 lock(&i->ref.lk);
          106                 lock(&s->ref.lk);
          107                 if(i->s == s && s->ref.ref == 1)
          108                         i->s = 0;
          109                 unlock(&i->ref.lk);
          110         }
          111         else
          112                 lock(&s->ref.lk);
          113 
          114         s->ref.ref--;
          115         if(s->ref.ref != 0) {
          116                 unlock(&s->ref.lk);
          117                 return;
          118         }
          119         unlock(&s->ref.lk);
          120 
          121         qlock(&s->lk);
          122         if(i)
          123                 putimage(i);
          124 
          125         emap = &s->map[s->mapsize];
          126         for(pp = s->map; pp < emap; pp++)
          127                 if(*pp)
          128                         freepte(s, *pp);
          129 
          130         qunlock(&s->lk);
          131         if(s->map != s->ssegmap)
          132                 free(s->map);
          133         if(s->profile != 0)
          134                 free(s->profile);
          135         free(s);
          136 }
          137 
          138 void
          139 relocateseg(Segment *s, ulong offset)
          140 {
          141         Page **pg, *x;
          142         Pte *pte, **p, **endpte;
          143 
          144         endpte = &s->map[s->mapsize];
          145         for(p = s->map; p < endpte; p++) {
          146                 if(*p == 0)
          147                         continue;
          148                 pte = *p;
          149                 for(pg = pte->first; pg <= pte->last; pg++) {
          150                         if((x = *pg))
          151                                 x->va += offset;
          152                 }
          153         }
          154 }
          155 
          156 Segment*
          157 dupseg(Segment **seg, int segno, int share)
          158 {
          159         int i, size;
          160         Pte *pte;
          161         Segment *n, *s;
          162 
          163         n = 0;
          164         s = seg[segno];
          165 
          166         qlock(&s->lk);
          167         if(waserror()){
          168                 qunlock(&s->lk);
          169                 nexterror();
          170         }
          171         switch(s->type&SG_TYPE) {
          172         case SG_TEXT:                /* New segment shares pte set */
          173         case SG_SHARED:
          174         case SG_PHYSICAL:
          175                 goto sameseg;
          176 
          177         case SG_STACK:
          178                 n = newseg(s->type, s->base, s->size);
          179                 break;
          180 
          181         case SG_BSS:                /* Just copy on write */
          182                 if(share)
          183                         goto sameseg;
          184                 n = newseg(s->type, s->base, s->size);
          185                 break;
          186 
          187         case SG_DATA:                /* Copy on write plus demand load info */
          188                 if(segno == TSEG){
          189                         poperror();
          190                         qunlock(&s->lk);
          191                         return data2txt(s);
          192                 }
          193 
          194                 if(share)
          195                         goto sameseg;
          196                 n = newseg(s->type, s->base, s->size);
          197 
          198                 incref(&s->image->ref);
          199                 n->image = s->image;
          200                 n->fstart = s->fstart;
          201                 n->flen = s->flen;
          202                 break;
          203         }
          204         size = s->mapsize;
          205         for(i = 0; i < size; i++)
          206                 if((pte = s->map[i]))
          207                         n->map[i] = ptecpy(pte);
          208 
          209         n->flushme = s->flushme;
          210         if(s->ref.ref > 1)
          211                 procflushseg(s);
          212         poperror();
          213         qunlock(&s->lk);
          214         return n;
          215 
          216 sameseg:
          217         incref(&s->ref);
          218         poperror();
          219         qunlock(&s->lk);
          220         return s;
          221 }
          222 
          223 void
          224 segpage(Segment *s, Page *p)
          225 {
          226         Pte **pte;
          227         ulong off;
          228         Page **pg;
          229 
          230         if(p->va < s->base || p->va >= s->top)
          231                 panic("segpage");
          232 
          233         off = p->va - s->base;
          234         pte = &s->map[off/PTEMAPMEM];
          235         if(*pte == 0)
          236                 *pte = ptealloc();
          237 
          238         pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
          239         *pg = p;
          240         if(pg < (*pte)->first)
          241                 (*pte)->first = pg;
          242         if(pg > (*pte)->last)
          243                 (*pte)->last = pg;
          244 }
          245 
          246 Image*
          247 attachimage(int type, Chan *c, ulong base, ulong len)
          248 {
          249         Image *i, **l;
          250 
          251         /* reclaim any free channels from reclaimed segments */
          252         if(imagealloc.nfreechan)
          253                 imagechanreclaim();
          254 
          255         lock(&imagealloc.lk);
          256 
          257         /*
          258          * Search the image cache for remains of the text from a previous
          259          * or currently running incarnation
          260          */
          261         for(i = ihash(c->qid.path); i; i = i->hash) {
          262                 if(c->qid.path == i->qid.path) {
          263                         lock(&i->ref.lk);
          264                         if(eqqid(c->qid, i->qid) &&
          265                            eqqid(c->mqid, i->mqid) &&
          266                            c->mchan == i->mchan &&
          267                            c->type == i->type) {
          268                                 goto found;
          269                         }
          270                         unlock(&i->ref.lk);
          271                 }
          272         }
          273 
          274         /*
          275          * imagereclaim dumps pages from the free list which are cached by image
          276          * structures. This should free some image structures.
          277          */
          278         while(!(i = imagealloc.free)) {
          279                 unlock(&imagealloc.lk);
          280                 imagereclaim();
          281                 sched();
          282                 lock(&imagealloc.lk);
          283         }
          284 
          285         imagealloc.free = i->next;
          286 
          287         lock(&i->ref.lk);
          288         incref(&c->ref);
          289         i->c = c;
          290         i->type = c->type;
          291         i->qid = c->qid;
          292         i->mqid = c->mqid;
          293         i->mchan = c->mchan;
          294         l = &ihash(c->qid.path);
          295         i->hash = *l;
          296         *l = i;
          297 found:
          298         unlock(&imagealloc.lk);
          299 
          300         if(i->s == 0) {
          301                 /* Disaster after commit in exec */
          302                 if(waserror()) {
          303                         unlock(&i->ref.lk);
          304                         pexit(Enovmem, 1);
          305                 }
          306                 i->s = newseg(type, base, len);
          307                 i->s->image = i;
          308                 i->ref.ref++;
          309                 poperror();
          310         }
          311         else
          312                 incref(&i->s->ref);
          313 
          314         return i;
          315 }
          316 
          317 static struct {
          318         int        calls;                        /* times imagereclaim was called */
          319         int        loops;                        /* times the main loop was run */
          320         uvlong        ticks;                        /* total time in the main loop */
          321         uvlong        maxt;                        /* longest time in main loop */
          322 } irstats;
          323 
          324 static void
          325 imagereclaim(void)
          326 {
          327         int n;
          328         Page *p;
          329         uvlong ticks;
          330 
          331         irstats.calls++;
          332         /* Somebody is already cleaning the page cache */
          333         if(!canqlock(&imagealloc.ireclaim))
          334                 return;
          335 
          336         lock(&palloc.lk);
          337         ticks = fastticks(nil);
          338         n = 0;
          339         /*
          340          * All the pages with images backing them are at the
          341          * end of the list (see putpage) so start there and work
          342          * backward.
          343          */
          344         for(p = palloc.tail; p && p->image && n<1000; p = p->prev) {
          345                 if(p->ref == 0 && canlock(&p->lk)) {
          346                         if(p->ref == 0) {
          347                                 n++;
          348                                 uncachepage(p);
          349                         }
          350                         unlock(&p->lk);
          351                 }
          352         }
          353         ticks = fastticks(nil) - ticks;
          354         unlock(&palloc.lk);
          355         irstats.loops++;
          356         irstats.ticks += ticks;
          357         if(ticks > irstats.maxt)
          358                 irstats.maxt = ticks;
          359         //print("T%llud+", ticks);
          360         qunlock(&imagealloc.ireclaim);
          361 }
          362 
          363 /*
          364  *  since close can block, this has to be called outside of
          365  *  spin locks.
          366  */
          367 static void
          368 imagechanreclaim(void)
          369 {
          370         Chan *c;
          371 
          372         /* Somebody is already cleaning the image chans */
          373         if(!canqlock(&imagealloc.fcreclaim))
          374                 return;
          375 
          376         /*
          377          * We don't have to recheck that nfreechan > 0 after we
          378          * acquire the lock, because we're the only ones who decrement 
          379          * it (the other lock contender increments it), and there's only
          380          * one of us thanks to the qlock above.
          381          */
          382         while(imagealloc.nfreechan > 0){
          383                 lock(&imagealloc.lk);
          384                 imagealloc.nfreechan--;
          385                 c = imagealloc.freechan[imagealloc.nfreechan];
          386                 unlock(&imagealloc.lk);
          387                 cclose(c);
          388         }
          389 
          390         qunlock(&imagealloc.fcreclaim);
          391 }
          392 
          393 void
          394 putimage(Image *i)
          395 {
          396         Chan *c, **cp;
          397         Image *f, **l;
          398 
          399         if(i->notext)
          400                 return;
          401 
          402         lock(&i->ref.lk);
          403         if(--i->ref.ref == 0) {
          404                 l = &ihash(i->qid.path);
          405                 mkqid(&i->qid, ~0, ~0, QTFILE);
          406                 unlock(&i->ref.lk);
          407                 c = i->c;
          408 
          409                 lock(&imagealloc.lk);
          410                 for(f = *l; f; f = f->hash) {
          411                         if(f == i) {
          412                                 *l = i->hash;
          413                                 break;
          414                         }
          415                         l = &f->hash;
          416                 }
          417 
          418                 i->next = imagealloc.free;
          419                 imagealloc.free = i;
          420 
          421                 /* defer freeing channel till we're out of spin lock's */
          422                 if(imagealloc.nfreechan == imagealloc.szfreechan){
          423                         imagealloc.szfreechan += NFREECHAN;
          424                         cp = malloc(imagealloc.szfreechan*sizeof(Chan*));
          425                         if(cp == nil)
          426                                 panic("putimage");
          427                         memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
          428                         free(imagealloc.freechan);
          429                         imagealloc.freechan = cp;
          430                 }
          431                 imagealloc.freechan[imagealloc.nfreechan++] = c;
          432                 unlock(&imagealloc.lk);
          433 
          434                 return;
          435         }
          436         unlock(&i->ref.lk);
          437 }
          438 
          439 long
          440 ibrk(ulong addr, int seg)
          441 {
          442         Segment *s, *ns;
          443         ulong newtop, newsize;
          444         int i, mapsize;
          445         Pte **map;
          446 
          447         s = up->seg[seg];
          448         if(s == 0)
          449                 error(Ebadarg);
          450 
          451         if(addr == 0)
          452                 return s->base;
          453 
          454         qlock(&s->lk);
          455 
          456         /* We may start with the bss overlapping the data */
          457         if(addr < s->base) {
          458                 if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {
          459                         qunlock(&s->lk);
          460                         error(Enovmem);
          461                 }
          462                 addr = s->base;
          463         }
          464 
          465         newtop = PGROUND(addr);
          466         newsize = (newtop-s->base)/BY2PG;
          467         if(newtop < s->top) {
          468                 mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
          469                 s->top = newtop;
          470                 s->size = newsize;
          471                 qunlock(&s->lk);
          472                 flushmmu();
          473                 return 0;
          474         }
          475 
          476         if(swapfull()){
          477                 qunlock(&s->lk);
          478                 error(Enoswap);
          479         }
          480 
          481         for(i = 0; i < NSEG; i++) {
          482                 ns = up->seg[i];
          483                 if(ns == 0 || ns == s)
          484                         continue;
          485                 if(newtop >= ns->base && newtop < ns->top) {
          486                         qunlock(&s->lk);
          487                         error(Esoverlap);
          488                 }
          489         }
          490 
          491         if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
          492                 qunlock(&s->lk);
          493                 error(Enovmem);
          494         }
          495         mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
          496         if(mapsize > s->mapsize){
          497                 map = smalloc(mapsize*sizeof(Pte*));
          498                 memmove(map, s->map, s->mapsize*sizeof(Pte*));
          499                 if(s->map != s->ssegmap)
          500                         free(s->map);
          501                 s->map = map;
          502                 s->mapsize = mapsize;
          503         }
          504 
          505         s->top = newtop;
          506         s->size = newsize;
          507         qunlock(&s->lk);
          508         return 0;
          509 }
          510 
          511 /*
          512  *  called with s->lk locked
          513  */
          514 void
          515 mfreeseg(Segment *s, ulong start, int pages)
          516 {
          517         int i, j, size;
          518         ulong soff;
          519         Page *pg;
          520         Page *list;
          521 
          522         soff = start-s->base;
          523         j = (soff&(PTEMAPMEM-1))/BY2PG;
          524 
          525         size = s->mapsize;
          526         list = nil;
          527         for(i = soff/PTEMAPMEM; i < size; i++) {
          528                 if(pages <= 0)
          529                         break;
          530                 if(s->map[i] == 0) {
          531                         pages -= PTEPERTAB-j;
          532                         j = 0;
          533                         continue;
          534                 }
          535                 while(j < PTEPERTAB) {
          536                         pg = s->map[i]->pages[j];
          537                         /*
          538                          * We want to zero s->map[i]->page[j] and putpage(pg),
          539                          * but we have to make sure other processors flush the
          540                          * entry from their TLBs before the page is freed.
          541                          * We construct a list of the pages to be freed, zero
          542                          * the entries, then (below) call procflushseg, and call
          543                          * putpage on the whole list.
          544                          *
          545                          * Swapped-out pages don't appear in TLBs, so it's okay
          546                          * to putswap those pages before procflushseg.
          547                          */
          548                         if(pg){
          549                                 if(onswap(pg))
          550                                         putswap(pg);
          551                                 else{
          552                                         pg->next = list;
          553                                         list = pg;
          554                                 }
          555                                 s->map[i]->pages[j] = 0;
          556                         }
          557                         if(--pages == 0)
          558                                 goto out;
          559                         j++;
          560                 }
          561                 j = 0;
          562         }
          563 out:
          564         /* flush this seg in all other processes */
          565         if(s->ref.ref > 1)
          566                 procflushseg(s);
          567 
          568         /* free the pages */
          569         for(pg = list; pg != nil; pg = list){
          570                 list = list->next;
          571                 putpage(pg);
          572         }
          573 }
          574 
          575 Segment*
          576 isoverlap(Proc *p, ulong va, int len)
          577 {
          578         int i;
          579         Segment *ns;
          580         ulong newtop;
          581 
          582         newtop = va+len;
          583         for(i = 0; i < NSEG; i++) {
          584                 ns = p->seg[i];
          585                 if(ns == 0)
          586                         continue;
          587                 if((newtop > ns->base && newtop <= ns->top) ||
          588                    (va >= ns->base && va < ns->top))
          589                         return ns;
          590         }
          591         return nil;
          592 }
          593 
          594 int
          595 addphysseg(Physseg* new)
          596 {
          597         Physseg *ps;
          598 
          599         /*
          600          * Check not already entered and there is room
          601          * for a new entry and the terminating null entry.
          602          */
          603         lock(&physseglock);
          604         for(ps = physseg; ps->name; ps++){
          605                 if(strcmp(ps->name, new->name) == 0){
          606                         unlock(&physseglock);
          607                         return -1;
          608                 }
          609         }
          610         if(ps-physseg >= nelem(physseg)-2){
          611                 unlock(&physseglock);
          612                 return -1;
          613         }
          614 
          615         *ps = *new;
          616         unlock(&physseglock);
          617 
          618         return 0;
          619 }
          620 
          621 int
          622 isphysseg(char *name)
          623 {
          624         Physseg *ps;
          625         int rv = 0;
          626 
          627         lock(&physseglock);
          628         for(ps = physseg; ps->name; ps++){
          629                 if(strcmp(ps->name, name) == 0){
          630                         rv = 1;
          631                         break;
          632                 }
          633         }
          634         unlock(&physseglock);
          635         return rv;
          636 }
          637 
          638 ulong
          639 segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
          640 {
          641         int sno;
          642         Segment *s, *os;
          643         Physseg *ps;
          644 
          645         if(va != 0 && va >= USTKTOP)
          646                 error(Ebadarg);
          647 
          648         vmemchr(name, 0, ~0);
          649 
          650         for(sno = 0; sno < NSEG; sno++)
          651                 if(p->seg[sno] == nil && sno != ESEG)
          652                         break;
          653 
          654         if(sno == NSEG)
          655                 error(Enovmem);
          656 
          657         /*
          658          *  first look for a global segment with the
          659          *  same name
          660          */
          661         if(_globalsegattach != nil){
          662                 s = (*_globalsegattach)(p, name);
          663                 if(s != nil){
          664                         p->seg[sno] = s;
          665                         return s->base;
          666                 }
          667         }
          668 
          669         len = PGROUND(len);
          670         if(len == 0)
          671                 error(Ebadarg);
          672 
          673         /*
          674          * Find a hole in the address space.
          675          * Starting at the lowest possible stack address - len,
          676          * check for an overlapping segment, and repeat at the
          677          * base of that segment - len until either a hole is found
          678          * or the address space is exhausted.
          679          */
          680         if(va == 0) {
          681                 va = p->seg[SSEG]->base - len;
          682                 for(;;) {
          683                         os = isoverlap(p, va, len);
          684                         if(os == nil)
          685                                 break;
          686                         va = os->base;
          687                         if(len > va)
          688                                 error(Enovmem);
          689                         va -= len;
          690                 }
          691         }
          692 
          693         va = va&~(BY2PG-1);
          694         if(isoverlap(p, va, len) != nil)
          695                 error(Esoverlap);
          696 
          697         for(ps = physseg; ps->name; ps++)
          698                 if(strcmp(name, ps->name) == 0)
          699                         goto found;
          700 
          701         error(Ebadarg);
          702 found:
          703         if(len > ps->size)
          704                 error(Enovmem);
          705 
          706         attr &= ~SG_TYPE;                /* Turn off what is not allowed */
          707         attr |= ps->attr;                /* Copy in defaults */
          708 
          709         s = newseg(attr, va, len/BY2PG);
          710         s->pseg = ps;
          711         p->seg[sno] = s;
          712 
          713         return va;
          714 }
          715 
          716 void
          717 pteflush(Pte *pte, int s, int e)
          718 {
          719 #if 0        // Not needed for Plan 9 VX - no swap
          720         int i;
          721         Page *p;
          722 
          723         for(i = s; i < e; i++) {
          724                 p = pte->pages[i];
          725                 if(pagedout(p) == 0)
          726                         memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
          727         }
          728 #endif
          729 }
          730 
          731 long
          732 syssegflush(uint32 *arg)
          733 {
          734         Segment *s;
          735         ulong addr, l;
          736         Pte *pte;
          737         int chunk, ps, pe, len;
          738 
          739         addr = arg[0];
          740         len = arg[1];
          741 
          742         while(len > 0) {
          743                 s = seg(up, addr, 1);
          744                 if(s == 0)
          745                         error(Ebadarg);
          746 
          747                 s->flushme = 1;
          748         more:
          749                 l = len;
          750                 if(addr+l > s->top)
          751                         l = s->top - addr;
          752 
          753                 ps = addr-s->base;
          754                 pte = s->map[ps/PTEMAPMEM];
          755                 ps &= PTEMAPMEM-1;
          756                 pe = PTEMAPMEM;
          757                 if(pe-ps > l){
          758                         pe = ps + l;
          759                         pe = (pe+BY2PG-1)&~(BY2PG-1);
          760                 }
          761                 if(pe == ps) {
          762                         qunlock(&s->lk);
          763                         error(Ebadarg);
          764                 }
          765 
          766                 if(pte)
          767                         pteflush(pte, ps/BY2PG, pe/BY2PG);
          768 
          769                 chunk = pe-ps;
          770                 len -= chunk;
          771                 addr += chunk;
          772 
          773                 if(len > 0 && addr < s->top)
          774                         goto more;
          775 
          776                 qunlock(&s->lk);
          777         }
          778         flushmmu();
          779         return 0;
          780 }
          781 
          782 void
          783 segclock(ulong pc)
          784 {
          785         Segment *s;
          786 
          787         s = up->seg[TSEG];
          788         if(s == 0 || s->profile == 0)
          789                 return;
          790 
          791         s->profile[0] += TK2MS(1);
          792         if(pc >= s->base && pc < s->top) {
          793                 pc -= s->base;
          794                 s->profile[pc>>LRESPROF] += TK2MS(1);
          795         }
          796 }
          797