Annotation of 43BSDReno/sys/kern/vm_proc.c, revision 1.1.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.