Annotation of Net2/vm/vm_glue.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * Copyright (c) 1991 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * The Mach Operating System project at Carnegie-Mellon University.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the University of
        !            19:  *     California, Berkeley and its contributors.
        !            20:  * 4. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *     @(#)vm_glue.c   7.8 (Berkeley) 5/15/91
        !            37:  *
        !            38:  *
        !            39:  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
        !            40:  * All rights reserved.
        !            41:  * 
        !            42:  * Permission to use, copy, modify and distribute this software and
        !            43:  * its documentation is hereby granted, provided that both the copyright
        !            44:  * notice and this permission notice appear in all copies of the
        !            45:  * software, derivative works or modified versions, and any portions
        !            46:  * thereof, and that both notices appear in supporting documentation.
        !            47:  * 
        !            48:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
        !            49:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
        !            50:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            51:  * 
        !            52:  * Carnegie Mellon requests users of this software to return to
        !            53:  *
        !            54:  *  Software Distribution Coordinator  or  [email protected]
        !            55:  *  School of Computer Science
        !            56:  *  Carnegie Mellon University
        !            57:  *  Pittsburgh PA 15213-3890
        !            58:  *
        !            59:  * any improvements or extensions that they make and grant Carnegie the
        !            60:  * rights to redistribute these changes.
        !            61:  */
        !            62: 
        !            63: #include "param.h"
        !            64: #include "systm.h"
        !            65: #include "proc.h"
        !            66: #include "resourcevar.h"
        !            67: #include "buf.h"
        !            68: #include "user.h"
        !            69: 
        !            70: #include "vm.h"
        !            71: #include "vm_page.h"
        !            72: #include "vm_kern.h"
        !            73: 
        !            74: int    avefree = 0;            /* XXX */
        !            75: unsigned maxdmap = MAXDSIZ;    /* XXX */
        !            76: int    readbuffers = 0;        /* XXX allow kgdb to read kernel buffer pool */
        !            77: 
        !            78: kernacc(addr, len, rw)
        !            79:        caddr_t addr;
        !            80:        int len, rw;
        !            81: {
        !            82:        boolean_t rv;
        !            83:        vm_offset_t saddr, eaddr;
        !            84:        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
        !            85: 
        !            86:        saddr = trunc_page(addr);
        !            87:        eaddr = round_page(addr+len-1);
        !            88:        rv = vm_map_check_protection(kernel_map, saddr, eaddr, prot);
        !            89:        /*
        !            90:         * XXX there are still some things (e.g. the buffer cache) that
        !            91:         * are managed behind the VM system's back so even though an
        !            92:         * address is accessible in the mind of the VM system, there may
        !            93:         * not be physical pages where the VM thinks there is.  This can
        !            94:         * lead to bogus allocation of pages in the kernel address space
        !            95:         * or worse, inconsistencies at the pmap level.  We only worry
        !            96:         * about the buffer cache for now.
        !            97:         */
        !            98:        if (!readbuffers && rv && (eaddr > (vm_offset_t)buffers &&
        !            99:                   saddr < (vm_offset_t)buffers + MAXBSIZE * nbuf))
        !           100:                rv = FALSE;
        !           101:        return(rv == TRUE);
        !           102: }
        !           103: 
        !           104: useracc(addr, len, rw)
        !           105:        caddr_t addr;
        !           106:        int len, rw;
        !           107: {
        !           108:        boolean_t rv;
        !           109:        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
        !           110: 
        !           111:        rv = vm_map_check_protection(&curproc->p_vmspace->vm_map,
        !           112:            trunc_page(addr), round_page(addr+len-1), prot);
        !           113:        return(rv == TRUE);
        !           114: }
        !           115: 
        !           116: #ifdef KGDB
        !           117: /*
        !           118:  * Change protections on kernel pages from addr to addr+len
        !           119:  * (presumably so debugger can plant a breakpoint).
        !           120:  * All addresses are assumed to reside in the Sysmap,
        !           121:  */
        !           122: chgkprot(addr, len, rw)
        !           123:        register caddr_t addr;
        !           124:        int len, rw;
        !           125: {
        !           126:        vm_prot_t prot = rw == B_READ ? VM_PROT_READ : VM_PROT_WRITE;
        !           127: 
        !           128:        vm_map_protect(kernel_map, trunc_page(addr),
        !           129:                       round_page(addr+len-1), prot, FALSE);
        !           130: }
        !           131: #endif
        !           132: 
        !           133: vslock(addr, len)
        !           134:        caddr_t addr;
        !           135:        u_int   len;
        !           136: {
        !           137:        vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
        !           138:                        round_page(addr+len-1), FALSE);
        !           139: }
        !           140: 
        !           141: vsunlock(addr, len, dirtied)
        !           142:        caddr_t addr;
        !           143:        u_int   len;
        !           144:        int dirtied;
        !           145: {
        !           146: #ifdef lint
        !           147:        dirtied++;
        !           148: #endif lint
        !           149:        vm_map_pageable(&curproc->p_vmspace->vm_map, trunc_page(addr),
        !           150:                        round_page(addr+len-1), TRUE);
        !           151: }
        !           152: 
        !           153: /*
        !           154:  * Implement fork's actions on an address space.
        !           155:  * Here we arrange for the address space to be copied or referenced,
        !           156:  * allocate a user struct (pcb and kernel stack), then call the
        !           157:  * machine-dependent layer to fill those in and make the new process
        !           158:  * ready to run.
        !           159:  * NOTE: the kernel stack may be at a different location in the child
        !           160:  * process, and thus addresses of automatic variables may be invalid
        !           161:  * after cpu_fork returns in the child process.  We do nothing here
        !           162:  * after cpu_fork returns.
        !           163:  */
        !           164: vm_fork(p1, p2, isvfork)
        !           165:        register struct proc *p1, *p2;
        !           166:        int isvfork;
        !           167: {
        !           168:        register struct user *up;
        !           169:        vm_offset_t addr;
        !           170: 
        !           171: #ifdef i386
        !           172:        /*
        !           173:         * avoid copying any of the parent's pagetables or other per-process
        !           174:         * objects that reside in the map by marking all of them non-inheritable
        !           175:         */
        !           176:        (void)vm_map_inherit(&p1->p_vmspace->vm_map,
        !           177:                UPT_MIN_ADDRESS-UPAGES*NBPG, VM_MAX_ADDRESS, VM_INHERIT_NONE);
        !           178: #endif
        !           179:        p2->p_vmspace = vmspace_fork(p1->p_vmspace);
        !           180: 
        !           181: #ifdef SYSVSHM
        !           182:        if (p1->p_vmspace->vm_shm)
        !           183:                shmfork(p1, p2, isvfork);
        !           184: #endif
        !           185: 
        !           186:        /*
        !           187:         * Allocate a wired-down (for now) pcb and kernel stack for the process
        !           188:         */
        !           189:        addr = kmem_alloc_pageable(kernel_map, ctob(UPAGES));
        !           190:        vm_map_pageable(kernel_map, addr, addr + ctob(UPAGES), FALSE);
        !           191:        up = (struct user *)addr;
        !           192:        p2->p_addr = up;
        !           193: 
        !           194:        /*
        !           195:         * p_stats and p_sigacts currently point at fields
        !           196:         * in the user struct but not at &u, instead at p_addr.
        !           197:         * Copy p_sigacts and parts of p_stats; zero the rest
        !           198:         * of p_stats (statistics).
        !           199:         */
        !           200:        p2->p_stats = &up->u_stats;
        !           201:        p2->p_sigacts = &up->u_sigacts;
        !           202:        up->u_sigacts = *p1->p_sigacts;
        !           203:        bzero(&up->u_stats.pstat_startzero,
        !           204:            (unsigned) ((caddr_t)&up->u_stats.pstat_endzero -
        !           205:            (caddr_t)&up->u_stats.pstat_startzero));
        !           206:        bcopy(&p1->p_stats->pstat_startcopy, &up->u_stats.pstat_startcopy,
        !           207:            ((caddr_t)&up->u_stats.pstat_endcopy -
        !           208:             (caddr_t)&up->u_stats.pstat_startcopy));
        !           209: 
        !           210: #ifdef i386
        !           211:        { u_int addr = UPT_MIN_ADDRESS - UPAGES*NBPG; struct vm_map *vp;
        !           212: 
        !           213:        vp = &p2->p_vmspace->vm_map;
        !           214:        (void)vm_map_pageable(vp, addr, 0xfe000000 - addr, TRUE);
        !           215:        (void)vm_deallocate(vp, addr, 0xfe000000 - addr);
        !           216:        (void)vm_allocate(vp, &addr, UPT_MAX_ADDRESS - addr, FALSE);
        !           217:        (void)vm_map_inherit(vp, addr, UPT_MAX_ADDRESS, VM_INHERIT_NONE);
        !           218:        }
        !           219: #endif
        !           220:        /*
        !           221:         * cpu_fork will copy and update the kernel stack and pcb,
        !           222:         * and make the child ready to run.  It marks the child
        !           223:         * so that it can return differently than the parent.
        !           224:         * It returns twice, once in the parent process and
        !           225:         * once in the child.
        !           226:         */
        !           227:        return (cpu_fork(p1, p2));
        !           228: }
        !           229: 
        !           230: /*
        !           231:  * Set default limits for VM system.
        !           232:  * Called for proc 0, and then inherited by all others.
        !           233:  */
        !           234: vm_init_limits(p)
        !           235:        register struct proc *p;
        !           236: {
        !           237: 
        !           238:        /*
        !           239:         * Set up the initial limits on process VM.
        !           240:         * Set the maximum resident set size to be all
        !           241:         * of (reasonably) available memory.  This causes
        !           242:         * any single, large process to start random page
        !           243:         * replacement once it fills memory.
        !           244:         */
        !           245:         p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
        !           246:         p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
        !           247:         p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
        !           248:         p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
        !           249:        p->p_rlimit[RLIMIT_RSS].rlim_cur = p->p_rlimit[RLIMIT_RSS].rlim_max =
        !           250:                ptoa(vm_page_free_count);
        !           251: }
        !           252: 
        !           253: #include "../vm/vm_pageout.h"
        !           254: 
        !           255: #ifdef DEBUG
        !           256: int    enableswap = 1;
        !           257: int    swapdebug = 0;
        !           258: #define        SDB_FOLLOW      1
        !           259: #define SDB_SWAPIN     2
        !           260: #define SDB_SWAPOUT    4
        !           261: #endif
        !           262: 
        !           263: /*
        !           264:  * Brutally simple:
        !           265:  *     1. Attempt to swapin every swaped-out, runnable process in
        !           266:  *        order of priority.
        !           267:  *     2. If not enough memory, wake the pageout daemon and let it
        !           268:  *        clear some space.
        !           269:  */
        !           270: sched()
        !           271: {
        !           272:        register struct proc *p;
        !           273:        register int pri;
        !           274:        struct proc *pp;
        !           275:        int ppri;
        !           276:        vm_offset_t addr;
        !           277:        vm_size_t size;
        !           278: 
        !           279: loop:
        !           280: #ifdef DEBUG
        !           281:        if (!enableswap) {
        !           282:                pp = NULL;
        !           283:                goto noswap;
        !           284:        }
        !           285: #endif
        !           286:        pp = NULL;
        !           287:        ppri = INT_MIN;
        !           288:        for (p = allproc; p != NULL; p = p->p_nxt)
        !           289:                if (p->p_stat == SRUN && (p->p_flag & SLOAD) == 0) {
        !           290:                        pri = p->p_time + p->p_slptime - p->p_nice * 8;
        !           291:                        if (pri > ppri) {
        !           292:                                pp = p;
        !           293:                                ppri = pri;
        !           294:                        }
        !           295:                }
        !           296: #ifdef DEBUG
        !           297:        if (swapdebug & SDB_FOLLOW)
        !           298:                printf("sched: running, procp %x pri %d\n", pp, ppri);
        !           299: noswap:
        !           300: #endif
        !           301:        /*
        !           302:         * Nothing to do, back to sleep
        !           303:         */
        !           304:        if ((p = pp) == NULL) {
        !           305:                sleep((caddr_t)&proc0, PVM);
        !           306:                goto loop;
        !           307:        }
        !           308: 
        !           309:        /*
        !           310:         * We would like to bring someone in.
        !           311:         * This part is really bogus cuz we could deadlock on memory
        !           312:         * despite our feeble check.
        !           313:         */
        !           314:        size = round_page(ctob(UPAGES));
        !           315:        addr = (vm_offset_t) p->p_addr;
        !           316:        if (vm_page_free_count > atop(size)) {
        !           317: #ifdef DEBUG
        !           318:                if (swapdebug & SDB_SWAPIN)
        !           319:                        printf("swapin: pid %d(%s)@%x, pri %d free %d\n",
        !           320:                               p->p_pid, p->p_comm, p->p_addr,
        !           321:                               ppri, vm_page_free_count);
        !           322: #endif
        !           323:                vm_map_pageable(kernel_map, addr, addr+size, FALSE);
        !           324:                (void) splclock();
        !           325:                if (p->p_stat == SRUN)
        !           326:                        setrq(p);
        !           327:                p->p_flag |= SLOAD;
        !           328:                (void) spl0();
        !           329:                p->p_time = 0;
        !           330:                goto loop;
        !           331:        }
        !           332:        /*
        !           333:         * Not enough memory, jab the pageout daemon and wait til the
        !           334:         * coast is clear.
        !           335:         */
        !           336: #ifdef DEBUG
        !           337:        if (swapdebug & SDB_FOLLOW)
        !           338:                printf("sched: no room for pid %d(%s), free %d\n",
        !           339:                       p->p_pid, p->p_comm, vm_page_free_count);
        !           340: #endif
        !           341:        (void) splhigh();
        !           342:        VM_WAIT;
        !           343:        (void) spl0();
        !           344: #ifdef DEBUG
        !           345:        if (swapdebug & SDB_FOLLOW)
        !           346:                printf("sched: room again, free %d\n", vm_page_free_count);
        !           347: #endif
        !           348:        goto loop;
        !           349: }
        !           350: 
        !           351: #define        swappable(p) \
        !           352:        (((p)->p_flag & (SSYS|SLOAD|SKEEP|SWEXIT|SPHYSIO)) == SLOAD)
        !           353: 
        !           354: /*
        !           355:  * Swapout is driven by the pageout daemon.  Very simple, we find eligible
        !           356:  * procs and unwire their u-areas.  We try to always "swap" at least one
        !           357:  * process in case we need the room for a swapin.
        !           358:  * If any procs have been sleeping/stopped for at least maxslp seconds,
        !           359:  * they are swapped.  Else, we swap the longest-sleeping or stopped process,
        !           360:  * if any, otherwise the longest-resident process.
        !           361:  */
        !           362: swapout_threads()
        !           363: {
        !           364:        register struct proc *p;
        !           365:        struct proc *outp, *outp2;
        !           366:        int outpri, outpri2;
        !           367:        int didswap = 0;
        !           368:        extern int maxslp;
        !           369: 
        !           370: #ifdef DEBUG
        !           371:        if (!enableswap)
        !           372:                return;
        !           373: #endif
        !           374:        outp = outp2 = NULL;
        !           375:        outpri = outpri2 = 0;
        !           376:        for (p = allproc; p != NULL; p = p->p_nxt) {
        !           377:                if (!swappable(p))
        !           378:                        continue;
        !           379:                switch (p->p_stat) {
        !           380:                case SRUN:
        !           381:                        if (p->p_time > outpri2) {
        !           382:                                outp2 = p;
        !           383:                                outpri2 = p->p_time;
        !           384:                        }
        !           385:                        continue;
        !           386:                        
        !           387:                case SSLEEP:
        !           388:                case SSTOP:
        !           389:                        if (p->p_slptime > maxslp) {
        !           390:                                swapout(p);
        !           391:                                didswap++;
        !           392:                        } else if (p->p_slptime > outpri) {
        !           393:                                outp = p;
        !           394:                                outpri = p->p_slptime;
        !           395:                        }
        !           396:                        continue;
        !           397:                }
        !           398:        }
        !           399:        /*
        !           400:         * If we didn't get rid of any real duds, toss out the next most
        !           401:         * likely sleeping/stopped or running candidate.  We only do this
        !           402:         * if we are real low on memory since we don't gain much by doing
        !           403:         * it (UPAGES pages).
        !           404:         */
        !           405:        if (didswap == 0 &&
        !           406:            vm_page_free_count <= atop(round_page(ctob(UPAGES)))) {
        !           407:                if ((p = outp) == 0)
        !           408:                        p = outp2;
        !           409: #ifdef DEBUG
        !           410:                if (swapdebug & SDB_SWAPOUT)
        !           411:                        printf("swapout_threads: no duds, try procp %x\n", p);
        !           412: #endif
        !           413:                if (p)
        !           414:                        swapout(p);
        !           415:        }
        !           416: }
        !           417: 
        !           418: swapout(p)
        !           419:        register struct proc *p;
        !           420: {
        !           421:        vm_offset_t addr;
        !           422:        vm_size_t size;
        !           423: 
        !           424: #ifdef DEBUG
        !           425:        if (swapdebug & SDB_SWAPOUT)
        !           426:                printf("swapout: pid %d(%s)@%x, stat %x pri %d free %d\n",
        !           427:                       p->p_pid, p->p_comm, p->p_addr, p->p_stat,
        !           428:                       p->p_slptime, vm_page_free_count);
        !           429: #endif
        !           430:        size = round_page(ctob(UPAGES));
        !           431:        addr = (vm_offset_t) p->p_addr;
        !           432: #ifdef hp300
        !           433:        /*
        !           434:         * Ugh!  u-area is double mapped to a fixed address behind the
        !           435:         * back of the VM system and accesses are usually through that
        !           436:         * address rather than the per-process address.  Hence reference
        !           437:         * and modify information are recorded at the fixed address and
        !           438:         * lost at context switch time.  We assume the u-struct and
        !           439:         * kernel stack are always accessed/modified and force it to be so.
        !           440:         */
        !           441:        {
        !           442:                register int i;
        !           443:                volatile long tmp;
        !           444: 
        !           445:                for (i = 0; i < UPAGES; i++) {
        !           446:                        tmp = *(long *)addr; *(long *)addr = tmp;
        !           447:                        addr += NBPG;
        !           448:                }
        !           449:                addr = (vm_offset_t) p->p_addr;
        !           450:        }
        !           451: #endif
        !           452:        vm_map_pageable(kernel_map, addr, addr+size, TRUE);
        !           453:        pmap_collect(vm_map_pmap(&p->p_vmspace->vm_map));
        !           454:        (void) splhigh();
        !           455:        p->p_flag &= ~SLOAD;
        !           456:        if (p->p_stat == SRUN)
        !           457:                remrq(p);
        !           458:        (void) spl0();
        !           459:        p->p_time = 0;
        !           460: }
        !           461: 
        !           462: /*
        !           463:  * The rest of these routines fake thread handling
        !           464:  */
        !           465: 
        !           466: void
        !           467: assert_wait(event, ruptible)
        !           468:        int event;
        !           469:        boolean_t ruptible;
        !           470: {
        !           471: #ifdef lint
        !           472:        ruptible++;
        !           473: #endif
        !           474:        curproc->p_thread = event;
        !           475: }
        !           476: 
        !           477: void
        !           478: thread_block()
        !           479: {
        !           480:        int s = splhigh();
        !           481: 
        !           482:        if (curproc->p_thread)
        !           483:                sleep((caddr_t)curproc->p_thread, PVM);
        !           484:        splx(s);
        !           485: }
        !           486: 
        !           487: thread_sleep(event, lock, ruptible)
        !           488:        int event;
        !           489:        simple_lock_t lock;
        !           490:        boolean_t ruptible;
        !           491: {
        !           492: #ifdef lint
        !           493:        ruptible++;
        !           494: #endif
        !           495:        int s = splhigh();
        !           496: 
        !           497:        curproc->p_thread = event;
        !           498:        simple_unlock(lock);
        !           499:        if (curproc->p_thread)
        !           500:                sleep((caddr_t)event, PVM);
        !           501:        splx(s);
        !           502: }
        !           503: 
        !           504: thread_wakeup(event)
        !           505:        int event;
        !           506: {
        !           507:        int s = splhigh();
        !           508: 
        !           509:        wakeup((caddr_t)event);
        !           510:        splx(s);
        !           511: }
        !           512: 
        !           513: /*
        !           514:  * DEBUG stuff
        !           515:  */
        !           516: 
        !           517: int indent = 0;
        !           518: 
        !           519: /*ARGSUSED2*/
        !           520: iprintf(a, b, c, d, e, f, g, h)
        !           521:        char *a;
        !           522: {
        !           523:        register int i;
        !           524: 
        !           525:        i = indent;
        !           526:        while (i >= 8) {
        !           527:                printf("\t");
        !           528:                i -= 8;
        !           529:        }
        !           530:        for (; i > 0; --i)
        !           531:                printf(" ");
        !           532:        printf(a, b, c, d, e, f, g, h);
        !           533: }

unix.superglobalmegacorp.com

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