250 likes | 436 Views
제 26 강 : main(). main(). main() (1550) initialize core (1568), clist, blist, … set up process #0 (1589) Special type -- no a.out, just ppda (1589) make ppda at the end of a.out. main, icode. (1613) buffer cache (1616) root directory (1627) newproc()
E N D
제26강 : main() main()
main() (1550) • initialize core (1568), clist, blist, … • set up process #0 (1589) • Special type -- no a.out, just ppda • (1589) make ppda at the end of a.out main, icode
(1613) buffer cache (1616) root directory (1627) newproc() So let’s go to newproc() (1826) (7-5) main calls newproc
newproc() 1826 (7-5-1) 1841 mpid global var -- PID 1846 find empty slot in proc[] 1848 p & rpp - for child (currently being born) 1859 up & rip - for current process (parent) parent Parent Child Child
parent • copy entire proc[] except for PID • (open file reference count)++ : • “f_” is fields within struct file • 1894 a1 - address of parent’s image • 1896 a2– address of available space Parent Child Child
user a.out user kernelstack sched • 1915 while (n--) copyseg(a1++, a2++) • copy swappable image(including ppda) • now child is ready • But child, is waiting in the ready queue • Child will be waken up by swtch() later • and return with value 1 (see 2247 in swtch()). • return(0) parent returns with 0. • A close look at Child • - a.out • - struct user • - kernel stack • - struct proc[ ] copied parent’s image
Where child has to be different • (7-5-1-b) • 1. Address of proc[] (1891) u (child) • 1848 p & rpp - for child • 1859 up & rip - for current process • 1891 struct user point to child temporarily • 1917 restore it back to parent’s • 2. Address of image (1913) proc[child] • 1894 a1 - address of parent’s image • 1896 a2– address of child (free space) • 3. Save SP/EP (1889) u (child) • this savu() is not for parent himself • parent is not giving up CPU here • so parent does not need u.u_rsav here • let savu() use u.u_rsav for child • CPU (SP|EP) u.u_rsav • When child wakes up in the future • child loads SP/EP from u.u_rsav (retu()) • child pops kernel stack using SP/EP • child returns from newproc() to main() kernel stack SP newproc 1627 EP main user user u.u_rsav (2528) this is kenel malloc(), not user library. this is size of (a.out + struct user)
Summary newproc() allocate & copy proc[ ] for child Image(PNEW) Image(PPARENT) copy a.out & copy struct user PNEW is now in ready state parent Parent Child Child
user a.out user kernelstack Summary newproc() allocate & copy proc[ ] for child Image(PNEW) Image(PPARENT) copy (a.out + user + kernel stack) PNEW is now in ready state sched Including p.p.d.a.
main calls newproc OK, back to main() 1627, 1st call to newproc() returned zero, While in newproc(), we created process #1 by making proc[PNEW] copying Image(PNEW) Image(PPARENT) Process #1 is now ready (waiting to run) Caller (parent) returns from newproc() with value zero, skips (1628-1636) sched() (1940) sched()sleep() sleep() swtch() context switch
1627 1550 main() 1826 newproc() 1637 1940 sched() You are Here 1968 2066 sleep() 2084 2178 swtch()
swtch(1) wakeup setrun Current process retires Process #0 runs
Selected process arises swtch(2) Pop stack for return address
2178: swtch() 2189: savu(u.u_rsav); 2191: /* Switch to scheduler's stack */ 2193: retu(proc[0].p_addr); 2201: /* Search for highest-priority runnable process */ 2203: i = NPROC; 2204: do { 2205: rp++; 2208: if(rp->p_stat==SRUN && (rp->p_flag&SLOAD)!=0) { 2209: if(rp->p_pri < n) { 2210: p = rp; 2211: n = rp->p_pri; 2212: } 2213: } 2214: } while(--i); 2215: /* 2228: retu(rp->p_addr); 2229: sureg(); 2247: return(1);
a.out PAR PDR CPU R0 R1 | S P E P user kernel stack kernel retu(proc[j]) 1. kernel’s 7th PAR points to new ppda 2. load CPU SP EP from new struct user a.out a.out user user kernel stack kernel stack p_addr p_addr p_addr proc[i] proc[j] proc[k] kernel struct proc[NPROC]
retu(proc[k]) 1. kernel’s 7th PAR points to new ppda 2. load CPU SP EP from new struct user a.out a.out PAR PDR a.out CPU R0 R1 | S P E P user user user kernel stack kernel stack kernel stack kernel p_addr p_addr p_addr proc[i] proc[j] proc[k] kernel struct proc[NPROC]
a.out PAR PDR CPU R0 R1 | S P E P user kernel stack kernel a.out PAR PDR CPU R0 R1 | S P E P user kernel stack kernel a.out PAR PDR CPU R0 R1 | S P E P user kernel stack kernel swtch () { retu(proc[0]) retu(rp); return } saveu(u) prepare to block caller 2193 proc #0 runs on CPU 2228 proc rp runs on CPU
Summary – swtch() 2189 savu(u) prepare to preempt CPU 2193 retu(proc[0]) CPU scheduler runs on CPU 2228 retu(proc[rp]) new process runs on CPU 2247 return(1) new process returns from swtch() • Pcaller wants to sleep • and calls swtch() • savu (u) prepare to • preempt CPU from Pcaller Pcaller P P P P Pscheduler 2. retu (proc[0]) gives CPU to scheduler (process #0) 3. scheduler selects the highest priority job retu (proc[new_process]) gives CPU to new job Phigh_pri
swtch() (2178) (8-2-2-t) • 2189 caller retires savu(u.u_rsav) • 2193 CPU scheduler (proc #0) wakes up • retu(proc[0].p_addr) • 2209 search proc table (maximum priority) • new proc is picked (2223 rp=p) • 2228 CPU given to new process • retu(rp->p_addr) • sureg() • set CPU user mapping registers (1739) • set user mode (memory mapping) registers • 2247 new process executes 2247 • return(1) -- pops return address from • kernel mode stack • return to where?) • returns to main() 1627 user k-stack SP newproc() 1627 EP main() user Selected process arises swtch(2) Pop stack for return address kernel mode stack of the new process (copied from P0)
Where child has to be different • (7-5-1-b) • 1. Address of proc[] (1891) u (child) • 1848 p & rpp - for child • 1859 up & rip - for current process • 1891 struct user point to child temporarily • 1917 restore it back to parent’s • 2. Address of image (1913) proc[child] • 1894 a1 - address of parent’s image • 1896 a2– address of child (free space) • 3. Save SP/EP (1889) u (child) • this savu() is not for parent himself • parent is not giving up CPU here • so parent does not need u.u_rsav here • let savu() use u.u_rsav for child • CPU (SP|EP) u.u_rsav • When child wakes up in the future • child loads SP/EP from u.u_rsav (retu()) • child pops kernel stack using SP/EP • child returns from newproc() to main() kernel stack SP newproc 1627 EP main user user u.u_rsav (2528) this is kenel malloc(), not user library. this is size of (a.out + struct user)
Booting • main() • make proc[0] – just ppda, no a,out • newproc • make proc[1] – by copying proc[0] • return from newproc with zero • if (newproc()) test fails • skip if () then { } • sched() sleep() swtch() • swtch() • retu(proc[0]) selects proc[1] • retu(proc[1]) • return(1) ---Now proc[1] is running -- • 1627 if (newproc()) test -- TRUE • into if () then { } • expand user space for P1’s a.out • copy icode[] from kernel to P1’s user space • return from kernel mode to user code • execute icode[] in user space • “ main() - - - exec(init) system call • P1 reenters kernel • exec() system call • read from disk • load init (user a,out) into memory • jump to user code (init) • ---Now proc[1] is /etc/init code • init process creates shell per tty • init gives CPU to shell (via swtch()) main calls newproc
ASM: Between Kernel & User • copyout(N, Mu, Mk) subyte(Mu, D) suword(Mu, D) • copyin(N, Mu, Mk) fubyte(Mu) fuword(Mu) N bytechar word • Mu, Mk: memory address fetch, set • N: count IPC, I/O • D:data set user a.out kernel a.out C: Between I/O buffer & User fetch • iomove() passc() cpass() • N byte char (K->U) char (K<-U) C functions (eventually call assembler functions above) struct user is used here for parameter values u_base: address to do I/O in user a.out u_count: byte count Sys Call Used for I/O IPC