📄 vm_proc.c
字号:
struct pte proto; size_t ods; register int size; register u_int v; if (change == 0) return; if (change % CLSIZE) panic("expand"); p = u.u_procp;#ifdef PGINPROF vmsizmon();#endif /* Update the sizes to reflect the change. */ ods = u.u_dsize; v = dptov(p, p->p_dsize); p->p_dsize += change; u.u_dsize += change; /* Compute the base of the allocated/freed region. */ base = u.u_pcb.pcb_p0br + u.u_tsize + ods; if (change < 0){ base += change; /* If we shrunk, give back the virtual memory. */ p->p_rssize -= vmemfree(base, -change); } /* If shrinking, clear pte's, otherwise */ /* initialize zero fill on demand pte's. */ *(int *)&proto = PG_UW; if (change < 0) change = -change; else { proto.pg_fod = 1; ((struct fpte *)&proto)->pg_fileno = PG_FZERO; cnt.v_nzfod += change; } base0 = base; size = change; while (--change >= 0) *base++ = proto; /* We changed mapping for the current process, */ /* so must update the hardware translation */ newptes(base0, v, size);}#endif vax#ifdef mips/* * Change the size of the data+stack regions of the process. * If the size is shrinking, it's easy-- just release virtual memory. * If it's growing, initalize new page table entries as * 'zero fill on demand' pages. */expand(change, region) int change, region;{ register struct proc *p; register struct pte *base; struct pte proto; size_t osize; int size; u_int v; int avail;XPRINTF(XPR_VM,"enter expand",0,0,0,0); p = u.u_procp; if (change == 0) return; if (change % CLSIZE) panic("expand");#ifdef PGINPROF vmsizmon();#endif /* * Update the sizes to reflect the change. Note that we may * swap as a result of a ptexpand, but this will work, because * the routines which swap out will get the current text and data * sizes from the arguments they are passed, and when the process * resumes the lengths in the proc structure are used to * build the new page tables. */ if (region == 0) { osize = u.u_dsize; v = dptov(p, p->p_dsize); avail = (p->p_datapt * NPTEPG) - p->p_dsize; p->p_dsize += change; u.u_dsize += change; if (change > avail) { ptexpand(clrnd(ctopt(change - avail)), osize, u.u_ssize, region); } base = p->p_databr + osize + (change > 0 ? 0 : change); } else { osize = u.u_ssize; avail = (p->p_stakpt * NPTEPG) - REDZONEPAGES - p->p_ssize; p->p_ssize += change; v = sptov(p, p->p_ssize - 1); u.u_ssize += change; if (change > avail) { ptexpand(clrnd(ctopt(change - avail)), u.u_dsize, osize, region); } base = (p->p_stakbr + p->p_stakpt * NPTEPG) - (p->p_ssize + REDZONEPAGES) + (change > 0 ? 0 : change); } /* * If we shrunk, give back the virtual memory. */ if (change < 0) { p->p_rssize -= vmemfree(base, -change); XPRINTF(XPR_VM, "expand p_rssize %d change %d", p->p_rssize, change, 0, 0); } /* * If shrinking, clear pte's, otherwise * initialize zero fill on demand pte's. */ *(int *)&proto = PG_UW; if (change < 0) change = -change; else { proto.pg_fod = 1; ((struct fpte *)&proto)->pg_fileno = PG_FZERO; cnt.v_nzfod += change; } size = change; while (--change >= 0) *base++ = proto; /* * We changed mapping for the current process, * so must update the hardware translation */ newptes(p, v, size);}smexpand(){XPRINTF(XPR_VM,"enter smexpand",0,0,0,0); /* wow! - rr */}#endif mips/* * Create a duplicate copy of the current process * in process slot p, which has been partially initialized * by newproc(). * * Could deadlock here if two large proc's get page tables * and then each gets part of his UPAGES if they then have * consumed all the available memory. This can only happen when * USRPTSIZE + UPAGES * NPROC > maxmem * which is impossible except on systems with tiny real memories, * when large procs stupidly fork() instead of vfork(). */procdup(p, isvfork) register struct proc *p;{ register struct file *fp; register int n; /* * Allocate page tables for new process, waiting * for memory to be free. */#ifdef mips XPRINTF(XPR_VM, "enter procdup pid = %d", p->p_pid, 0, 0, 0);#endif mips#ifdef vax while (vgetpt(p, vmemall) == 0) {#endif vax#ifdef mips if (isvfork == 0) { while (vgetpt(p, vmemall, vmemfree) == 0) {#endif mips kmapwnt++;#ifdef mips XPRINTF(XPR_VM, "procdup sleeping vgetpt failed pid = %d", p->p_pid, 0, 0, 0);#endif mips sleep((caddr_t)kernelmap, PSWP+4); }#ifdef mips }#endif mips /* * Snapshot the current u. area pcb and get a u. * for the new process, a copy of our u. */#ifdef vax resume(pcbb(u.u_procp));#endif vax#ifdef mips XPRINTF(XPR_VM, "procdup calling vgetu pid = %d", p->p_pid, 0, 0, 0); save();#endif mips (void) vgetu(p, vmemall, Forkmap, &forkutl, &u); /* * Arrange for a non-local goto when the new process * is started, to resume here, returning nonzero from savectx. */ forkutl.u_pcb.pcb_sswap = (int *)&u.u_ssave;#ifdef vax if (savectx(&forkutl.u_ssave))#endif vax#ifdef mips XPRINTF(XPR_VM, "procdup calling setjmp pid = %d", p->p_pid, 0, 0, 0); /* * TODO: can this setjmp() be avoided? perhaps only update PC. */ if (setjmp(&forkutl.u_ssave))#endif mips /* * Return 1 in child. */ return (1); /* 001 * Increase reference counts on shared objects * and remove INUSE reference to inode. */ for (n = 0; n <= u.u_omax; n++) { fp = u.u_ofile[n]; if (fp == NULL) continue; fp->f_count++; forkutl.u_pofile[n] &= ~(UF_INUSE); } /* * If the new process is being created in vfork(), then * exchange vm resources with it. We want to end up with * just a u. area and an empty p0 region, so initialize the * prototypes in the other area before the exchange. */ if (isvfork) {#ifdef vax forkutl.u_pcb.pcb_p0lr = u.u_pcb.pcb_p0lr & AST_CLR; forkutl.u_pcb.pcb_p1lr = P1PAGES - HIGHPAGES;#endif#ifdef mips /* * I think this is a bug on the VAX verion anyway. * The child is started with an empty page table and * then the parent and child swap page tables. The above * statement has no effect because the parent will not * run again in user mode until after it gets its page * table back. * Copying resched isn't really necessary, I'm not sure * why they copy the AST bits on the VAX. */ forkutl.u_pcb.pcb_resched = u.u_pcb.pcb_resched;#endif vpassvm(u.u_procp, p, &u, &forkutl, Forkmap);#ifdef mips clear_tlbmappings(p);#endif mips /* * Return 0 in parent. */ return (0); } /* * A real fork; clear vm statistics of new process * and link into the new text segment. * Equivalent things happen during vfork() in vpassvm(). */ bzero((caddr_t)&forkutl.u_ru, sizeof (struct rusage)); bzero((caddr_t)&forkutl.u_cru, sizeof (struct rusage)); forkutl.u_dmap = u.u_cdmap; forkutl.u_smap = u.u_csmap; forkutl.u_outime = 0; /* * Attach to the text segment. */ if (p->p_textp) { p->p_textp->x_count++;#ifdef GFSDEBUG if(p->p_textp->x_freef || p->p_textp->x_freeb) { cprintf("procdup: pid %d xp 0x%x on free list\n", p->p_pid, p->p_textp); panic("procdup"); }#endif#ifdef mips while (xlink(p) == 0) { kmapwnt++;#ifdef mips XPRINTF(XPR_VM, "procdup sleeping xlink failed pid = %d", p->p_pid, 0, 0, 0);#endif mips sleep((caddr_t)kernelmap, PSWP+4); }#endif mips#ifdef vax xlink(p);#endif vax }#ifdef mips XPRINTF(XPR_VM, "procdup calling clear_tlbmappings pid = %d", p->p_pid, 0, 0, 0); clear_tlbmappings(p);#endif mips /* attach all shared memory segments SHMEM */ if(p->p_smbeg != 0) { smfork(u.u_procp, p); } /* * Duplicate data and stack space of current process * in the new process. */ vmdup(p, dptopte(p, 0), dptov(p, 0), p->p_dsize, CDATA); vmdup(p, sptopte(p, p->p_ssize - 1), sptov(p, p->p_ssize - 1), p->p_ssize, CSTACK); /* * Return 0 in parent. */ return (0);}/* * this is where all the work for fork is done. * we take out the loops for i=0,1 and put the code inline * we also use only registers in the while loop * As far as this goes, we only run with CLSIZE==2 anyways!!!! */vmdup(p, pte, v, count, type)#if CLSIZE==2 register struct proc *p;#else struct proc *p;#endif register struct pte *pte; register unsigned v; register size_t count; int type;{ register struct pte *opte = vtopte(u.u_procp, v); register struct cmap *c;#if CLSIZE!=2 register int i;#endif#ifdef mips XPRINTF(XPR_VM,"enter vmdup",0,0,0,0);#endif mips while (count != 0) { count -= CLSIZE; if (opte->pg_fod) { v += CLSIZE;#if CLSIZE==2 *(int *)pte++ = *(int *)opte++; *(int *)pte++ = *(int *)opte++;#else for (i = 0; i < CLSIZE; i++) *(int *)pte++ = *(int *)opte++;#endif continue; }#ifdef vax opte += CLSIZE;#endif vax (void) vmemall(pte, CLSIZE, p, type); p->p_rssize += CLSIZE;#if CLSIZE==2 copyseg((caddr_t)ctob(v), pte->pg_pfnum); *(int *)(pte) |= (PG_V|PG_M) + PG_UW; c = &cmap[pgtocm(pte->pg_pfnum)]; /* grab before bumping pte */ v++;pte++; copyseg((caddr_t)ctob(v), pte->pg_pfnum); *(int *)(pte) |= (PG_V|PG_M) + PG_UW; v++;pte++; MUNLOCK(c); /* unlock page */#else for (i = 0; i < CLSIZE; i++) { copyseg((caddr_t)ctob(v+i), (pte+i)->pg_pfnum); *(int *)(pte+i) |= (PG_V|PG_M) + PG_UW; } v += CLSIZE; c = &cmap[pgtocm(pte->pg_pfnum)]; MUNLOCK(c); pte += CLSIZE;#endif#ifdef mips opte += CLSIZE;#endif mips } p->p_flag |= SPTECHG;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -