Annotation of 43BSDReno/sys/kern/vm_proc.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution is only permitted until one year after the first shipment
        !             6:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
        !             7:  * binary forms are permitted provided that: (1) source distributions retain
        !             8:  * this entire copyright notice and comment, and (2) distributions including
        !             9:  * binaries display the following acknowledgement:  This product includes
        !            10:  * software developed by the University of California, Berkeley and its
        !            11:  * contributors'' in the documentation or other materials provided with the
        !            12:  * distribution and in all advertising materials mentioning features or use
        !            13:  * of this software.  Neither the name of the University nor the names of
        !            14:  * its contributors may be used to endorse or promote products derived from
        !            15:  * this software without specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  *
        !            20:  *     @(#)vm_proc.c   7.11 (Berkeley) 6/30/90
        !            21:  */
        !            22: 
        !            23: #include "param.h"
        !            24: #include "systm.h"
        !            25: #include "user.h"
        !            26: #include "proc.h"
        !            27: #include "map.h"
        !            28: #include "cmap.h"
        !            29: #include "text.h"
        !            30: #include "vm.h"
        !            31: 
        !            32: #include "machine/pte.h"
        !            33: #include "machine/mtpr.h"
        !            34: #include "machine/cpu.h"
        !            35: 
        !            36: /*
        !            37:  * Get virtual memory resources for a new process.
        !            38:  * Called after page tables are allocated, but before they
        !            39:  * are initialized, we initialize the memory management registers,
        !            40:  * and then expand the page tables for the data and stack segments
        !            41:  * creating zero fill pte's there.  Text pte's are set up elsewhere.
        !            42:  *
        !            43:  * SHOULD FREE EXTRA PAGE TABLE PAGES HERE OR SOMEWHERE.
        !            44:  */
        !            45: vgetvm(ts, ds, ss)
        !            46:        segsz_t ts, ds, ss;
        !            47: {
        !            48: 
        !            49: #if defined(vax)
        !            50:        u.u_pcb.pcb_p0lr = AST_NONE;
        !            51:        setp0lr(ts);
        !            52:        setp1lr(P1PAGES - HIGHPAGES);
        !            53: #endif
        !            54: #if defined(tahoe)
        !            55:        setp0lr(ts);
        !            56:        setp1lr(0);
        !            57:        setp2lr(P2PAGES - HIGHPAGES);
        !            58: #endif
        !            59: #if defined(hp300) || defined(i386)
        !            60:        setp0lr(LOWPAGES + ts);
        !            61:        setp1lr(P1PAGES - HIGHPAGES);
        !            62: #endif
        !            63:        u.u_procp->p_tsize = ts;
        !            64:        u.u_tsize = ts;
        !            65:        expand((int)ss, 1);
        !            66:        expand((int)ds, 0);
        !            67: }
        !            68: 
        !            69: /*
        !            70:  * Release the virtual memory resources (memory
        !            71:  * pages, and swap area) associated with the current process.
        !            72:  * Caller must not be swappable.  Used at exit or execl.
        !            73:  */
        !            74: vrelvm()
        !            75: {
        !            76:        register struct proc *p = u.u_procp;
        !            77:        
        !            78:        /*
        !            79:         * Release memory; text first, then data and stack pages.
        !            80:         */
        !            81:        xfree();
        !            82:        p->p_rssize -= vmemfree(dptopte(p, 0), (int)p->p_dsize);
        !            83:        p->p_rssize -= vmemfree(sptopte(p, p->p_ssize - 1), (int)p->p_ssize);
        !            84:        if (p->p_rssize != 0)
        !            85:                panic("vrelvm rss");
        !            86:        /*
        !            87:         * Wait for all page outs to complete, then
        !            88:         * release swap space.
        !            89:         */
        !            90:        p->p_swrss = 0;
        !            91:        while (p->p_poip)
        !            92:                sleep((caddr_t)&p->p_poip, PSWP+1);
        !            93:        (void) vsexpand((segsz_t)0, &u.u_dmap, 1);
        !            94:        (void) vsexpand((segsz_t)0, &u.u_smap, 1);
        !            95:        p->p_tsize = 0;
        !            96:        p->p_dsize = 0;
        !            97:        p->p_ssize = 0;
        !            98:        u.u_tsize = 0;
        !            99:        u.u_dsize = 0;
        !           100:        u.u_ssize = 0;
        !           101: }
        !           102: 
        !           103: /*
        !           104:  * Pass virtual memory resources from p to q.
        !           105:  * P's u. area is up, q's is uq.  Used internally
        !           106:  * when starting/ending a vfork().
        !           107:  */
        !           108: vpassvm(p, q, up, uq, umap)
        !           109:        register struct proc *p, *q;
        !           110:        register struct user *up, *uq;
        !           111:        struct pte *umap;
        !           112: {
        !           113: 
        !           114:        /*
        !           115:         * Pass fields related to vm sizes.
        !           116:         */
        !           117:        uq->u_tsize = q->p_tsize = p->p_tsize; up->u_tsize = p->p_tsize = 0;
        !           118:        uq->u_dsize = q->p_dsize = p->p_dsize; up->u_dsize = p->p_dsize = 0;
        !           119:        uq->u_ssize = q->p_ssize = p->p_ssize; up->u_ssize = p->p_ssize = 0;
        !           120:        q->p_mmsize = p->p_mmsize; p->p_mmsize = 0;
        !           121: 
        !           122:        /*
        !           123:         * Pass proc table paging statistics.
        !           124:         */
        !           125:        q->p_swrss = p->p_swrss; p->p_swrss = 0;
        !           126:        q->p_rssize = p->p_rssize; p->p_rssize = 0;
        !           127:        q->p_poip = p->p_poip; p->p_poip = 0;
        !           128: 
        !           129:        /*
        !           130:         * Relink text segment.
        !           131:         */
        !           132:        q->p_textp = p->p_textp;
        !           133:        xrepl(p, q);
        !           134:        p->p_textp = 0;
        !           135: 
        !           136:        /*
        !           137:         * Pass swap space maps.
        !           138:         */
        !           139:        uq->u_dmap = up->u_dmap; up->u_dmap = zdmap;
        !           140:        uq->u_smap = up->u_smap; up->u_smap = zdmap;
        !           141: 
        !           142:        /*
        !           143:         * Pass u. paging statistics.
        !           144:         */
        !           145:        uq->u_outime = up->u_outime; up->u_outime = 0;
        !           146:        uq->u_ru = up->u_ru;
        !           147:        bzero((caddr_t)&up->u_ru, sizeof (struct rusage));
        !           148:        uq->u_cru = up->u_cru;
        !           149:        bzero((caddr_t)&up->u_cru, sizeof (struct rusage));
        !           150: 
        !           151:        /*
        !           152:         * And finally, pass the page tables themselves.
        !           153:         * On return we are running on the other set of
        !           154:         * page tables, but still with the same u. area.
        !           155:         */
        !           156:        vpasspt(p, q, up, uq, umap);
        !           157: #ifdef MAPMEM
        !           158:        /*
        !           159:         * Exchange mapped memory resources.
        !           160:         */
        !           161:        if (up->u_mmap)
        !           162:                mmvfork(up, uq);
        !           163: #endif
        !           164: }
        !           165: 
        !           166: /*
        !           167:  * Change the size of the data+stack regions of the process.
        !           168:  * If the size is shrinking, it's easy-- just release virtual memory.
        !           169:  * If it's growing, initalize new page table entries as 
        !           170:  * 'zero fill on demand' pages.
        !           171:  */
        !           172: expand(change, region)
        !           173:        int change, region;
        !           174: {
        !           175:        register struct proc *p;
        !           176: #if defined(vax)
        !           177:        register struct pte *base, *p0, *p1;
        !           178:        int p0lr, p1lr;
        !           179: #endif
        !           180: #if defined(tahoe)
        !           181:        register struct pte *base, *p0, *p2;
        !           182:        int p0lr, p2lr;
        !           183: #endif
        !           184: #if defined(hp300) || defined(i386)
        !           185:        register struct pte *base;
        !           186:        int p0lr, p1lr;
        !           187: #endif
        !           188:        struct pte proto;
        !           189:        struct pte *base0;
        !           190:        segsz_t ods, oss;
        !           191:        int size;
        !           192:        u_int v;
        !           193: 
        !           194:        p = u.u_procp;
        !           195:        if (change == 0)
        !           196:                return;
        !           197:        if (change % CLSIZE)
        !           198:                panic("expand");
        !           199: 
        !           200: #ifdef PGINPROF
        !           201:        vmsizmon();
        !           202: #endif
        !           203: 
        !           204:        /*
        !           205:         * Update the sizes to reflect the change.  Note that we may
        !           206:         * swap as a result of a ptexpand, but this will work, because
        !           207:         * the routines which swap out will get the current text and data
        !           208:         * sizes from the arguments they are passed, and when the process
        !           209:         * resumes the lengths in the proc structure are used to 
        !           210:         * build the new page tables.
        !           211:         */
        !           212:        ods = u.u_dsize;
        !           213:        oss = u.u_ssize;
        !           214:        if (region == 0) {
        !           215:                v = dptov(p, change > 0 ? p->p_dsize : p->p_dsize+change);
        !           216:                p->p_dsize += change;
        !           217:                u.u_dsize += change;
        !           218:        } else {
        !           219:                v = sptov(p, change > 0 ? p->p_ssize-1+change : p->p_ssize-1);
        !           220:                p->p_ssize += change;
        !           221:                u.u_ssize += change;
        !           222:        }
        !           223: 
        !           224:        /*
        !           225:         * Compute the end of the text+data regions and the beginning
        !           226:         * of the stack region in the page tables,
        !           227:         * and expand the page tables if necessary.
        !           228:         */
        !           229: #if defined(vax)
        !           230:        p0 = u.u_pcb.pcb_p0br + (u.u_pcb.pcb_p0lr&~AST_CLR);
        !           231:        p1 = u.u_pcb.pcb_p1br + (u.u_pcb.pcb_p1lr&~PME_CLR);
        !           232:        if (change > p1 - p0)
        !           233:                ptexpand(clrnd(ctopt(change - (p1 - p0))), ods, p->p_mmsize, oss);
        !           234: #endif
        !           235: #if defined(tahoe)
        !           236:        p0 = u.u_pcb.pcb_p0br + u.u_pcb.pcb_p0lr;
        !           237:        p2 = u.u_pcb.pcb_p2br + u.u_pcb.pcb_p2lr;
        !           238:        if (change > p2 - p0)
        !           239:                ptexpand(clrnd(ctopt(change - (p2 - p0))), ods, p->p_mmsize, oss);
        !           240: #endif
        !           241: #if defined(hp300) || defined(i386)
        !           242:        size = ptsize(p) - u.u_pcb.pcb_szpt;
        !           243:        if (size > 0)
        !           244:                ptexpand(size, ods, p->p_mmsize, oss);
        !           245: #endif
        !           246:        /* PTEXPAND SHOULD GIVE BACK EXCESS PAGE TABLE PAGES */
        !           247: 
        !           248:        /*
        !           249:         * Compute the base of the allocated/freed region.
        !           250:         */
        !           251: #if defined(vax)
        !           252:        p0lr = u.u_pcb.pcb_p0lr&~AST_CLR;
        !           253:        p1lr = u.u_pcb.pcb_p1lr&~PME_CLR;
        !           254: #endif
        !           255: #if defined(tahoe)
        !           256:        p0lr = u.u_pcb.pcb_p0lr;
        !           257:        p2lr = u.u_pcb.pcb_p2lr;
        !           258: #endif
        !           259: #if defined(hp300) || defined(i386)
        !           260:        p0lr = u.u_pcb.pcb_p0lr;
        !           261:        p1lr = u.u_pcb.pcb_p1lr;
        !           262: #endif
        !           263:        if (region == 0) {
        !           264: #ifdef MAPMEM
        !           265:                size = dptov(u.u_procp, ods);
        !           266: #else
        !           267:                size = p0lr;
        !           268: #endif
        !           269:                base = u.u_pcb.pcb_p0br + size + (change > 0 ? 0 : change);
        !           270:        } else {
        !           271: #if defined(vax) || defined(hp300) || defined(i386)
        !           272:                size = p1lr;
        !           273:                base = u.u_pcb.pcb_p1br + size - (change > 0 ? change : 0);
        !           274: #endif
        !           275: #if defined(tahoe)
        !           276:                size = p2lr;
        !           277:                base = u.u_pcb.pcb_p2br + size - (change > 0 ? change : 0);
        !           278: #endif
        !           279:        }
        !           280: 
        !           281:        /*
        !           282:         * If we shrank, give back the virtual memory.
        !           283:         */
        !           284:        if (change < 0)
        !           285:                p->p_rssize -= vmemfree(base, -change);
        !           286: 
        !           287:        /*
        !           288:         * Update the processor length registers and copies in the pcb.
        !           289:         */
        !           290:        if (region == 0) {
        !           291:                if (u.u_procp->p_mmsize == 0)
        !           292:                        setp0lr(size + change);
        !           293:        } else
        !           294: #if defined(vax) || defined(hp300) || defined(i386)
        !           295:                setp1lr(size - change);
        !           296: #endif
        !           297: #if defined(tahoe)
        !           298:                setp2lr(size - change);
        !           299: #endif
        !           300: 
        !           301:        /*
        !           302:         * If shrinking, clear pte's, otherwise
        !           303:         * initialize zero fill on demand pte's.
        !           304:         */
        !           305:        *(int *)&proto = PG_UW;
        !           306:        if (change < 0)
        !           307:                change = -change;
        !           308:        else {
        !           309:                proto.pg_fod = 1;
        !           310:                ((struct fpte *)&proto)->pg_fileno = PG_FZERO;
        !           311:                cnt.v_nzfod += change;
        !           312:        }
        !           313:        base0 = base;
        !           314:        size = change;
        !           315:        while (--change >= 0)
        !           316:                *base++ = proto;
        !           317: 
        !           318:        /*
        !           319:         * We changed mapping for the current process,
        !           320:         * so must update the hardware translation
        !           321:         */
        !           322:        newptes(base0, v, size);
        !           323: }
        !           324: 
        !           325: /*
        !           326:  * Create a duplicate copy of the current process
        !           327:  * in process slot p, which has been partially initialized
        !           328:  * by newproc().
        !           329:  *
        !           330:  * Could deadlock here if two large proc's get page tables
        !           331:  * and then each gets part of his UPAGES if they then have
        !           332:  * consumed all the available memory.  This can only happen when
        !           333:  *     USRPTSIZE + UPAGES * NPROC > maxmem
        !           334:  * which is impossible except on systems with tiny real memories,
        !           335:  * when large procs stupidly fork() instead of vfork().
        !           336:  */
        !           337: procdup(p, isvfork)
        !           338:        register struct proc *p;
        !           339: {
        !           340: 
        !           341:        /*
        !           342:         * Allocate page tables for new process, waiting
        !           343:         * for memory to be free.
        !           344:         */
        !           345:        while (vgetpt(p, vmemall) == 0) {
        !           346:                kmapwnt++;
        !           347:                sleep((caddr_t)kernelmap, PSWP+4);
        !           348:        }
        !           349:        /*
        !           350:         * Snapshot the current u. area pcb and get a u.
        !           351:         * for the new process, a copy of our u.
        !           352:         */
        !           353:        resume(pcbb(u.u_procp));
        !           354:        (void) vgetu(p, vmemall, Forkmap, &forkutl, &u);
        !           355: #if defined(tahoe)
        !           356:        /*
        !           357:         * Define new cache data key.
        !           358:        */
        !           359:        ckey_cnt[forkutl.u_procp->p_ckey]++;
        !           360:        forkutl.u_procp->p_dkey = getdatakey();
        !           361:        forkutl.u_pcb.pcb_savacc.faddr = (float *)NULL;
        !           362: #endif
        !           363: 
        !           364:        /*
        !           365:         * Arrange for a non-local goto when the new process
        !           366:         * is started, to resume here, returning nonzero from setjmp.
        !           367:         */
        !           368:        forkutl.u_pcb.pcb_sswap = (int *)&u.u_ssave;
        !           369:        if (savectx(&forkutl.u_ssave)) {
        !           370: #ifdef MAPMEM
        !           371:                if ((u.u_procp->p_flag & SVFORK) == 0 && u.u_mmap)
        !           372:                        (void) mmfork((struct user *)0, &u);
        !           373: #endif
        !           374:                /*
        !           375:                 * Return 1 in child.
        !           376:                 */
        !           377:                return (1);
        !           378:        }
        !           379: 
        !           380:        /*
        !           381:         * If the new process is being created in vfork(), then
        !           382:         * exchange vm resources with it.  We want to end up with
        !           383:         * just a u. area and an empty p0 region, so initialize the
        !           384:         * prototypes in the other area before the exchange.
        !           385:         */
        !           386:        if (isvfork) {
        !           387: #if defined(vax)
        !           388:                forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr & AST_CLR;
        !           389:                forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES;
        !           390: #endif
        !           391: #if defined(tahoe)
        !           392:                forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr;
        !           393:                forkutl.u_pcb.pcb_p1lr = 0;
        !           394:                forkutl.u_pcb.pcb_p2lr = P2PAGES - HIGHPAGES;
        !           395: #endif
        !           396: #if defined(hp300) || defined(i386)
        !           397:                forkutl.u_pcb.pcb_p0lr = 0;
        !           398:                forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES;
        !           399: #endif
        !           400:                vpassvm(u.u_procp, p, &u, &forkutl, Forkmap);
        !           401:                /*
        !           402:                 * Return 0 in parent.
        !           403:                 */
        !           404:                return (0);
        !           405:        }
        !           406:        /*
        !           407:         * A real fork; clear vm statistics of new process
        !           408:         * and link into the new text segment.
        !           409:         * Equivalent things happen during vfork() in vpassvm().
        !           410:         */
        !           411:        bzero((caddr_t)&forkutl.u_ru, sizeof (struct rusage));
        !           412:        bzero((caddr_t)&forkutl.u_cru, sizeof (struct rusage));
        !           413:        forkutl.u_dmap = u.u_cdmap;
        !           414:        forkutl.u_smap = u.u_csmap;
        !           415:        forkutl.u_outime = 0;
        !           416: 
        !           417:        /*
        !           418:         * Attach to the text segment.
        !           419:         */
        !           420:        if (p->p_textp) {
        !           421:                p->p_textp->x_count++;
        !           422:                xlink(p);
        !           423:        }
        !           424: 
        !           425: #ifdef MAPMEM
        !           426:        /*
        !           427:         * We do this before duplicating the address space since vmdup()
        !           428:         * might block causing Forkmap/forkutl to become invalid
        !           429:         */
        !           430:        if (u.u_mmap)
        !           431:                (void) mmfork(&u, &forkutl);
        !           432: #endif
        !           433:        /*
        !           434:         * Duplicate data and stack space of current process
        !           435:         * in the new process.
        !           436:         */
        !           437:        vmdup(p, dptopte(p, 0), dptov(p, 0), p->p_dsize, CDATA);
        !           438:        vmdup(p, sptopte(p, p->p_ssize - 1), sptov(p, p->p_ssize - 1), p->p_ssize, CSTACK);
        !           439: 
        !           440:        /*
        !           441:         * Return 0 in parent.
        !           442:         */
        !           443:        return (0);
        !           444: }
        !           445: 
        !           446: vmdup(p, pte, v, count, type)
        !           447:        struct proc *p;
        !           448:        register struct pte *pte;
        !           449:        register unsigned v;
        !           450:        register segsz_t count;
        !           451:        int type;
        !           452: {
        !           453:        register struct pte *opte = vtopte(u.u_procp, v);
        !           454:        register int i;
        !           455:        register struct cmap *c;
        !           456: 
        !           457:        while (count != 0) {
        !           458:                count -= CLSIZE;
        !           459:                if (opte->pg_fod) {
        !           460:                        v += CLSIZE;
        !           461:                        for (i = 0; i < CLSIZE; i++)
        !           462:                                *(int *)pte++ = *(int *)opte++;
        !           463:                        continue;
        !           464:                }
        !           465:                opte += CLSIZE;
        !           466:                (void) vmemall(pte, CLSIZE, p, type);
        !           467:                p->p_rssize += CLSIZE;
        !           468:                for (i = 0; i < CLSIZE; i++) {
        !           469:                        copyseg((caddr_t)ctob(v+i), (pte+i)->pg_pfnum);
        !           470:                        *(int *)(pte+i) |= (PG_V|PG_M) + PG_UW;
        !           471:                }
        !           472:                v += CLSIZE;
        !           473:                c = &cmap[pgtocm(pte->pg_pfnum)];
        !           474:                MUNLOCK(c);
        !           475:                pte += CLSIZE;
        !           476:        }
        !           477:        p->p_flag |= SPTECHG;
        !           478: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.