diff options
author | Robert Morris <[email protected]> | 2019-05-31 09:45:59 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2019-05-31 09:45:59 -0400 |
commit | 2ec1959fd1016a18ef3b2d154ce7076be8f237e4 (patch) | |
tree | 1aa75252085964283b3a2c735771f4da02346517 /proc.c | |
parent | 0f90388c893d1924e89e2e4d2187eda0004e9d73 (diff) | |
download | xv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.tar.gz xv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.tar.bz2 xv6-labs-2ec1959fd1016a18ef3b2d154ce7076be8f237e4.zip |
fork/wait/exit work
Diffstat (limited to 'proc.c')
-rw-r--r-- | proc.c | 285 |
1 files changed, 149 insertions, 136 deletions
@@ -1,18 +1,20 @@ #include "types.h" -#include "defs.h" #include "param.h" #include "memlayout.h" -#include "mmu.h" -#include "x86.h" +#include "riscv.h" #include "proc.h" #include "spinlock.h" +#include "defs.h" struct { struct spinlock lock; struct proc proc[NPROC]; } ptable; -static struct proc *initproc; +// XXX riscv move somewhere else +struct cpu cpus[NCPU]; + +struct proc *initproc; int nextpid = 1; extern void forkret(void); @@ -22,57 +24,36 @@ extern void sysexit(void); static void wakeup1(void *chan); +extern char trampstart[]; // trampoline.S + void -pinit(void) +procinit(void) { initlock(&ptable.lock, "ptable"); } -// Must be called with interrupts disabled +// Must be called with interrupts disabled. +// XXX riscv int cpuid() { - return mycpu()-cpus; -} - -// Must be called with interrupts disabled to avoid the caller being -// rescheduled between reading lapicid and running through the loop. -struct cpu* -getmycpu(void) -{ - int apicid, i; - - if(readeflags()&FL_IF) - panic("getmycpu called with interrupts enabled\n"); - - apicid = lapicid(); - // APIC IDs are not guaranteed to be contiguous. - for (i = 0; i < ncpu; ++i) { - if (cpus[i].apicid == apicid) - return &cpus[i]; - } - panic("unknown apicid\n"); + return 0; } -// Return this core's cpu struct using %gs. %gs points this core's struct -// cpu. Offet 24 in struct cpu is cpu. +// Return this core's cpu struct. +// XXX riscv struct cpu* mycpu(void) { struct cpu *c; - asm volatile("mov %%gs:24, %0" : "=r" (c)); + c = &cpus[0]; return c; } // Disable interrupts so that we are not rescheduled // while reading proc from the cpu structure +// XXX riscv struct proc* myproc(void) { - struct cpu *c; - struct proc *p; - pushcli(); - c = mycpu(); - p = c->proc; - popcli(); - return p; + return cpus[0].proc; } //PAGEBREAK: 32 @@ -84,7 +65,6 @@ static struct proc* allocproc(void) { struct proc *p; - char *sp; acquire(&ptable.lock); @@ -101,56 +81,73 @@ found: release(&ptable.lock); - // Allocate kernel stack. + // Allocate a page for the kernel stack. if((p->kstack = kalloc()) == 0){ p->state = UNUSED; return 0; } - sp = p->kstack + KSTACKSIZE; - // Leave room for syscall frame. - sp -= sizeof *p->sf; + // Allocate a trapframe page. + if((p->tf = (struct trapframe *)kalloc()) == 0){ + p->state = UNUSED; + return 0; + } - if ((uint64) sp % 16) - panic("misaligned sp"); + // An empty user page table. + p->pagetable = uvmcreate(); - p->sf = (struct sysframe*)sp; + // map the trampoline code (for system call return) + // at the highest user virtual address. + // only the supervisor uses it, on the way + // to/from user space, so not PTE_U. + mappages(p->pagetable, TRAMPOLINE, PGSIZE, + (uint64)trampstart, PTE_R | PTE_X); - // Set up new context to start executing at forkret, - // which returns to sysexit. - sp -= sizeof(uint64); - *(uint64*)sp = (uint64)sysexit; + // map the trapframe, for trampoline.S. + mappages(p->pagetable, (TRAMPOLINE - PGSIZE), PGSIZE, + (uint64)(p->tf), PTE_R | PTE_W); - sp -= sizeof *p->context; - p->context = (struct context*)sp; - memset(p->context, 0, sizeof *p->context); - p->context->rip = (uint64)forkret; + // Set up new context to start executing at forkret, + // which returns to user space. + memset(&p->context, 0, sizeof p->context); + p->context.ra = (uint64)forkret; + p->context.sp = (uint64)p->kstack + PGSIZE; return p; } +// XXX hack because I don't know how to incorporate initcode +// into the kernel binary. just the exec system call, no arguments. +// manually copied from initcode.asm. +unsigned char initcode[] = { + 0x85, 0x48, // li a7, 1 -- SYS_fork + 0x73, 0x00, 0x00, 0x00, // ecall + 0x8d, 0x48, // li a7, 3 -- SYS_wait + 0x73, 0x00, 0x00, 0x00, // ecall + 0x89, 0x48, // li a7, 2 -- SYS_exit + 0x73, 0x00, 0x00, 0x00, // ecall +}; + //PAGEBREAK: 32 // Set up first user process. void userinit(void) { struct proc *p; - extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); - initproc = p; - if((p->pgdir = setupkvm()) == 0) - panic("userinit: out of memory?"); - inituvm(p->pgdir, _binary_initcode_start, (uint64)_binary_initcode_size); + + uvminit(p->pagetable, initcode, sizeof(initcode)); p->sz = PGSIZE; - memset(p->sf, 0, sizeof(*p->sf)); - p->sf->r11 = FL_IF; - p->sf->rsp = PGSIZE; - p->sf->rcx = 0; // beginning of initcode.S + + // prepare for the very first kernel->user. + p->tf->epc = 0; + p->tf->sp = PGSIZE; safestrcpy(p->name, "initcode", sizeof(p->name)); - p->cwd = namei("/"); + // XXX riscv + //p->cwd = namei("/"); // this assignment to p->state lets other cores // run this process. the acquire forces the above @@ -163,62 +160,65 @@ userinit(void) release(&ptable.lock); } +#if 0 + // Grow current process's memory by n bytes. // Return 0 on success, -1 on failure. int growproc(int n) { uint sz; - struct proc *curproc = myproc(); + struct proc *p = myproc(); - sz = curproc->sz; + sz = p->sz; if(n > 0){ - if((sz = allocuvm(curproc->pgdir, sz, sz + n)) == 0) + if((sz = allocuvm(p->pagetable, sz, sz + n)) == 0) return -1; } else if(n < 0){ - if((sz = deallocuvm(curproc->pgdir, sz, sz + n)) == 0) + if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0) return -1; } - curproc->sz = sz; - switchuvm(curproc); + p->sz = sz; + switchuvm(p); return 0; } +#endif -// Create a new process copying p as the parent. -// Sets up stack to return as if from system call. -// Caller must set state of returned proc to RUNNABLE. +// Create a new process, copying p as the parent. +// Sets up child kernel stack to return as if from system call. int fork(void) { int i, pid; struct proc *np; - struct proc *curproc = myproc(); + struct proc *p = myproc(); // Allocate process. if((np = allocproc()) == 0){ return -1; } - // Copy process state from proc. - if((np->pgdir = copyuvm(curproc->pgdir, curproc->sz)) == 0){ - kfree(np->kstack); - np->kstack = 0; - np->state = UNUSED; - return -1; - } - np->sz = curproc->sz; - np->parent = curproc; - *np->sf = *curproc->sf; + // Copy user memory from parent to child. + uvmcopy(p->pagetable, np->pagetable, p->sz); + np->sz = p->sz; - // Clear %eax so that fork returns 0 in the child. - np->sf->rax = 0; + np->parent = p; + // copy saved user registers. + *(np->tf) = *(p->tf); + + // Cause fork to return 0 in the child. + np->tf->a0 = 0; + +#if 0 // XXX riscv + // increment reference counts on open file descriptors. for(i = 0; i < NOFILE; i++) - if(curproc->ofile[i]) - np->ofile[i] = filedup(curproc->ofile[i]); - np->cwd = idup(curproc->cwd); + if(p->ofile[i]) + np->ofile[i] = filedup(p->ofile[i]); + np->cwd = idup(p->cwd); +#endif - safestrcpy(np->name, curproc->name, sizeof(curproc->name)); + safestrcpy(np->name, p->name, sizeof(p->name)); pid = np->pid; @@ -233,46 +233,48 @@ fork(void) // Exit the current process. Does not return. // An exited process remains in the zombie state -// until its parent calls wait() to find out it exited. +// until its parent calls wait(). void exit(void) { - struct proc *curproc = myproc(); - struct proc *p; + struct proc *p = myproc(); + struct proc *pp; int fd; - if(curproc == initproc) + if(p == initproc) panic("init exiting"); +#if 0 // XXX riscv // Close all open files. for(fd = 0; fd < NOFILE; fd++){ - if(curproc->ofile[fd]){ - fileclose(curproc->ofile[fd]); - curproc->ofile[fd] = 0; + if(p->ofile[fd]){ + fileclose(p->ofile[fd]); + p->ofile[fd] = 0; } } begin_op(); - iput(curproc->cwd); + iput(p->cwd); end_op(); - curproc->cwd = 0; +#endif + p->cwd = 0; acquire(&ptable.lock); // Parent might be sleeping in wait(). - wakeup1(curproc->parent); + wakeup1(p->parent); // Pass abandoned children to init. - for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ - if(p->parent == curproc){ - p->parent = initproc; - if(p->state == ZOMBIE) + for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){ + if(pp->parent == p){ + pp->parent = initproc; + if(pp->state == ZOMBIE) wakeup1(initproc); } } // Jump into the scheduler, never to return. - curproc->state = ZOMBIE; + p->state = ZOMBIE; sched(); panic("zombie exit"); } @@ -282,42 +284,47 @@ exit(void) int wait(void) { - struct proc *p; + struct proc *np; int havekids, pid; - struct proc *curproc = myproc(); + struct proc *p = myproc(); acquire(&ptable.lock); for(;;){ // Scan through table looking for exited children. havekids = 0; - for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ - if(p->parent != curproc) + for(np = ptable.proc; np < &ptable.proc[NPROC]; np++){ + if(np->parent != p) continue; havekids = 1; - if(p->state == ZOMBIE){ + if(np->state == ZOMBIE){ // Found one. - pid = p->pid; - kfree(p->kstack); - p->kstack = 0; - freevm(p->pgdir, p->sz); - p->pid = 0; - p->parent = 0; - p->name[0] = 0; - p->killed = 0; - p->state = UNUSED; + pid = np->pid; + kfree(np->kstack); + np->kstack = 0; + kfree((void*)np->tf); + np->tf = 0; + unmappages(np->pagetable, TRAMPOLINE, PGSIZE, 0); + unmappages(np->pagetable, TRAMPOLINE-PGSIZE, PGSIZE, 0); + uvmfree(np->pagetable, np->sz); + np->pagetable = 0; + np->pid = 0; + np->parent = 0; + np->name[0] = 0; + np->killed = 0; + np->state = UNUSED; release(&ptable.lock); return pid; } } // No point waiting if we don't have any children. - if(!havekids || curproc->killed){ + if(!havekids || p->killed){ release(&ptable.lock); return -1; } // Wait for children to exit. (See wakeup1 call in proc_exit.) - sleep(curproc, &ptable.lock); //DOC: wait-sleep + sleep(p, &ptable.lock); //DOC: wait-sleep } } @@ -338,7 +345,8 @@ scheduler(void) c->proc = 0; for(;;){ // Enable interrupts on this processor. - sti(); + // XXX riscv + //sti(); // Loop over process table looking for process to run. acquire(&ptable.lock); @@ -350,11 +358,11 @@ scheduler(void) // to release ptable.lock and then reacquire it // before jumping back to us. c->proc = p; - switchuvm(p); p->state = RUNNING; - swtch(&(c->scheduler), p->context); - switchkvm(); + printf("switch...\n"); + swtch(&c->scheduler, &p->context); + printf("switch returned\n"); // Process is done running for now. // It should have changed its p->state before coming back. @@ -380,14 +388,10 @@ sched(void) if(!holding(&ptable.lock)) panic("sched ptable.lock"); - if(mycpu()->ncli != 1) - panic("sched locks"); if(p->state == RUNNING) panic("sched running"); - if(readeflags()&FL_IF) - panic("sched interruptible"); intena = mycpu()->intena; - swtch(&p->context, mycpu()->scheduler); + swtch(&p->context, &mycpu()->scheduler); mycpu()->intena = intena; } @@ -402,24 +406,29 @@ yield(void) } // A fork child's very first scheduling by scheduler() -// will swtch here. "Return" to user space. +// will swtch to forkret. void forkret(void) { + struct proc *p = myproc(); + static int first = 1; // Still holding ptable.lock from scheduler. release(&ptable.lock); + printf("entering forkret\n"); + if (first) { // Some initialization functions must be run in the context // of a regular process (e.g., they call sleep), and thus cannot // be run from main(). first = 0; - iinit(ROOTDEV); - initlog(ROOTDEV); + // XXX riscv + //iinit(ROOTDEV); + //initlog(ROOTDEV); } - - // Return to "caller", actually trapret (see allocproc). + + usertrapret(); } // Atomically release lock and sleep on chan. @@ -483,6 +492,8 @@ wakeup(void *chan) release(&ptable.lock); } +#if 0 + // Kill the process with the given pid. // Process won't exit until it returns // to user space (see trap in trap.c). @@ -533,12 +544,14 @@ procdump(void) state = states[p->state]; else state = "???"; - cprintf("%d %s %s", p->pid, state, p->name); + printf("%d %s %s", p->pid, state, p->name); if(p->state == SLEEPING){ getcallerpcs((uint64*)p->context->rbp+2, pc); for(i=0; i<10 && pc[i] != 0; i++) - cprintf(" %p", pc[i]); + printf(" %p", pc[i]); } - cprintf("\n"); + printf("\n"); } } + +#endif |