2 #include "../port/lib.h"
6 #include "../port/error.h"
8 static void imagereclaim(void);
9 static void imagechanreclaim(void);
14 * Attachable segment types
16 static Physseg physseg[10] = {
17 { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 },
18 { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 },
22 static Lock physseglock;
26 #define ihash(s) imagealloc.hash[s%IHASHSIZE]
27 static struct Imagealloc
31 Image *hash[IHASHSIZE];
32 QLock ireclaim; /* mutex on reclaiming free images */
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 */
40 Segment* (*_globalsegattach)(Proc*, char*);
47 imagealloc.free = xalloc(conf.nimage*sizeof(Image));
48 if(imagealloc.free == nil)
49 panic("initseg: no memory for Image");
50 ie = &imagealloc.free[conf.nimage-1];
51 for(i = imagealloc.free; i < ie; i++)
54 imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
55 if(imagealloc.freechan == nil)
56 panic("initseg: no memory for Chan");
57 imagealloc.szfreechan = NFREECHAN;
61 newseg(int type, ulong base, ulong size)
66 if(size > (SEGMAPSIZE*PTEPERTAB))
69 s = smalloc(sizeof(Segment));
73 s->top = base+(size*BY2PG);
75 s->sema.prev = &s->sema;
76 s->sema.next = &s->sema;
78 mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
79 if(mapsize > nelem(s->ssegmap)){
81 if(mapsize > (SEGMAPSIZE*PTEPERTAB))
82 mapsize = (SEGMAPSIZE*PTEPERTAB);
83 s->map = smalloc(mapsize*sizeof(Pte*));
88 s->mapsize = nelem(s->ssegmap);
107 if(i->s == s && s->ref == 1)
125 emap = &s->map[s->mapsize];
126 for(pp = s->map; pp < emap; pp++)
131 if(s->map != s->ssegmap)
139 relocateseg(Segment *s, ulong offset)
142 Pte *pte, **p, **endpte;
144 endpte = &s->map[s->mapsize];
145 for(p = s->map; p < endpte; p++) {
149 for(pg = pte->first; pg <= pte->last; pg++) {
157 dupseg(Segment **seg, int segno, int share)
171 switch(s->type&SG_TYPE) {
172 case SG_TEXT: /* New segment shares pte set */
178 n = newseg(s->type, s->base, s->size);
181 case SG_BSS: /* Just copy on write */
184 n = newseg(s->type, s->base, s->size);
187 case SG_DATA: /* Copy on write plus demand load info */
196 n = newseg(s->type, s->base, s->size);
200 n->fstart = s->fstart;
205 for(i = 0; i < size; i++)
207 n->map[i] = ptecpy(pte);
209 n->flushme = s->flushme;
224 segpage(Segment *s, Page *p)
230 if(p->va < s->base || p->va >= s->top)
233 off = p->va - s->base;
234 pte = &s->map[off/PTEMAPMEM];
238 pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
240 if(pg < (*pte)->first)
242 if(pg > (*pte)->last)
247 attachimage(int type, Chan *c, ulong base, ulong len)
251 /* reclaim any free channels from reclaimed segments */
252 if(imagealloc.nfreechan)
258 * Search the image cache for remains of the text from a previous
259 * or currently running incarnation
261 for(i = ihash(c->qid.path); i; i = i->hash) {
262 if(c->qid.path == i->qid.path) {
264 if(eqqid(c->qid, i->qid) &&
265 eqqid(c->mqid, i->mqid) &&
266 c->mchan == i->mchan &&
267 c->type == i->type) {
275 * imagereclaim dumps pages from the free list which are cached by image
276 * structures. This should free some image structures.
278 while(!(i = imagealloc.free)) {
285 imagealloc.free = i->next;
294 l = &ihash(c->qid.path);
301 /* Disaster after commit in exec */
306 i->s = newseg(type, base, len);
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 */
332 /* Somebody is already cleaning the page cache */
333 if(!canqlock(&imagealloc.ireclaim))
337 ticks = fastticks(nil);
340 * All the pages with images backing them are at the
341 * end of the list (see putpage) so start there and work
344 for(p = palloc.tail; p && p->image && n<1000; p = p->prev) {
345 if(p->ref == 0 && canlock(p)) {
353 ticks = fastticks(nil) - ticks;
356 irstats.ticks += ticks;
357 if(ticks > irstats.maxt)
358 irstats.maxt = ticks;
359 //print("T%llud+", ticks);
360 qunlock(&imagealloc.ireclaim);
364 * since close can block, this has to be called outside of
368 imagechanreclaim(void)
372 /* Somebody is already cleaning the image chans */
373 if(!canqlock(&imagealloc.fcreclaim))
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.
382 while(imagealloc.nfreechan > 0){
384 imagealloc.nfreechan--;
385 c = imagealloc.freechan[imagealloc.nfreechan];
390 qunlock(&imagealloc.fcreclaim);
404 l = &ihash(i->qid.path);
405 mkqid(&i->qid, ~0, ~0, QTFILE);
410 for(f = *l; f; f = f->hash) {
418 i->next = imagealloc.free;
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*));
427 memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
428 free(imagealloc.freechan);
429 imagealloc.freechan = cp;
431 imagealloc.freechan[imagealloc.nfreechan++] = c;
440 ibrk(ulong addr, int seg)
443 ulong newtop, newsize;
456 /* We may start with the bss overlapping the data */
458 if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {
465 newtop = PGROUND(addr);
466 newsize = (newtop-s->base)/BY2PG;
467 if(newtop < s->top) {
469 * do not shrink a segment shared with other procs, as the
470 * to-be-freed address space may have been passed to the kernel
471 * already by another proc and is past the validaddr stage.
477 mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
485 for(i = 0; i < NSEG; i++) {
487 if(ns == 0 || ns == s)
489 if(newtop >= ns->base && newtop < ns->top) {
495 if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
499 mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
500 if(mapsize > s->mapsize){
501 map = smalloc(mapsize*sizeof(Pte*));
502 memmove(map, s->map, s->mapsize*sizeof(Pte*));
503 if(s->map != s->ssegmap)
506 s->mapsize = mapsize;
516 * called with s->lk locked
519 mcountseg(Segment *s)
525 for(i = 0; i < s->mapsize; i++){
528 map = s->map[i]->pages;
529 for(j = 0; j < PTEPERTAB; j++)
537 * called with s->lk locked
540 mfreeseg(Segment *s, ulong start, int pages)
547 soff = start-s->base;
548 j = (soff&(PTEMAPMEM-1))/BY2PG;
552 for(i = soff/PTEMAPMEM; i < size; i++) {
556 pages -= PTEPERTAB-j;
560 while(j < PTEPERTAB) {
561 pg = s->map[i]->pages[j];
563 * We want to zero s->map[i]->page[j] and putpage(pg),
564 * but we have to make sure other processors flush the
565 * entry from their TLBs before the page is freed.
566 * We construct a list of the pages to be freed, zero
567 * the entries, then (below) call procflushseg, and call
568 * putpage on the whole list.
570 * Swapped-out pages don't appear in TLBs, so it's okay
571 * to putswap those pages before procflushseg.
580 s->map[i]->pages[j] = 0;
589 /* flush this seg in all other processes */
594 for(pg = list; pg != nil; pg = list){
601 isoverlap(Proc *p, ulong va, int len)
608 for(i = 0; i < NSEG; i++) {
612 if((newtop > ns->base && newtop <= ns->top) ||
613 (va >= ns->base && va < ns->top))
620 addphysseg(Physseg* new)
625 * Check not already entered and there is room
626 * for a new entry and the terminating null entry.
629 for(ps = physseg; ps->name; ps++){
630 if(strcmp(ps->name, new->name) == 0){
631 unlock(&physseglock);
635 if(ps-physseg >= nelem(physseg)-2){
636 unlock(&physseglock);
641 unlock(&physseglock);
647 isphysseg(char *name)
653 for(ps = physseg; ps->name; ps++){
654 if(strcmp(ps->name, name) == 0){
659 unlock(&physseglock);
664 segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
670 if(va != 0 && va >= USTKTOP)
673 validaddr((ulong)name, 1, 0);
674 vmemchr(name, 0, ~0);
676 for(sno = 0; sno < NSEG; sno++)
677 if(p->seg[sno] == nil && sno != ESEG)
684 * first look for a global segment with the
687 if(_globalsegattach != nil){
688 s = (*_globalsegattach)(p, name);
700 * Find a hole in the address space.
701 * Starting at the lowest possible stack address - len,
702 * check for an overlapping segment, and repeat at the
703 * base of that segment - len until either a hole is found
704 * or the address space is exhausted. Ensure that we don't
708 for (os = p->seg[SSEG]; os != nil; os = isoverlap(p, va, len)) {
717 if(va == 0 || va >= USTKTOP)
721 if(isoverlap(p, va, len) != nil)
724 for(ps = physseg; ps->name; ps++)
725 if(strcmp(name, ps->name) == 0)
733 attr &= ~SG_TYPE; /* Turn off what is not allowed */
734 attr |= ps->attr; /* Copy in defaults */
736 s = newseg(attr, va, len/BY2PG);
744 pteflush(Pte *pte, int s, int e)
749 for(i = s; i < e; i++) {
752 memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
757 syssegflush(ulong *arg)
762 int chunk, ps, pe, len;
768 s = seg(up, addr, 1);
779 pte = s->map[ps/PTEMAPMEM];
784 pe = (pe+BY2PG-1)&~(BY2PG-1);
792 pteflush(pte, ps/BY2PG, pe/BY2PG);
798 if(len > 0 && addr < s->top)
813 if(s == 0 || s->profile == 0)
816 s->profile[0] += TK2MS(1);
817 if(pc >= s->base && pc < s->top) {
819 s->profile[pc>>LRESPROF] += TK2MS(1);