vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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