|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.