Mercurial > hg > Members > innparusu > xv6_rpi_port
diff source/proc.c @ 0:c450faca55f4
Init
author | Tatsuki IHA <innparusu@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 22 Oct 2017 18:25:39 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/proc.c Sun Oct 22 18:25:39 2017 +0900 @@ -0,0 +1,453 @@ +/***************************************************************** +* proc.c +* adapted from MIT xv6 by Zhiyi Huang, hzy@cs.otago.ac.nz +* University of Otago +* +********************************************************************/ + + + +#include "types.h" +#include "defs.h" +#include "param.h" +#include "memlayout.h" +#include "mmu.h" +#include "arm.h" +#include "proc.h" +#include "spinlock.h" + +struct { + struct spinlock lock; + struct proc proc[NPROC]; +} ptable; + +static struct proc *initproc; + +int first_sched = 1; +int nextpid = 1; +extern void forkret(void); +extern void trapret(void); + +static void wakeup1(void *chan); + +void +pinit(void) +{ + memset(&ptable, 0, sizeof(ptable)); + initlock(&ptable.lock, "ptable"); + +} + +//PAGEBREAK: 32 +// Look in the process table for an UNUSED proc. +// If found, change state to EMBRYO and initialize +// state required to run in the kernel. +// Otherwise return 0. +static struct proc* +allocproc(void) +{ + struct proc *p; + char *sp; + + acquire(&ptable.lock); + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) + if(p->state == UNUSED) + goto found; + release(&ptable.lock); + return 0; + +found: + p->state = EMBRYO; + p->pid = nextpid++; + release(&ptable.lock); + + // Allocate kernel stack. + if((p->kstack = kalloc()) == 0){ + p->state = UNUSED; + return 0; + } + memset(p->kstack, 0, PGSIZE); + sp = p->kstack + KSTACKSIZE; + + // Leave room for trap frame. + sp -= sizeof *p->tf; + p->tf = (struct trapframe*)sp; + + // Set up new context to start executing at forkret, + // which returns to trapret. + + sp -= sizeof *p->context; + p->context = (struct context*)sp; + memset(p->context, 0, sizeof *p->context); + p->context->pc = (uint)forkret; + p->context->lr = (uint)trapret; + + return p; +} + +//PAGEBREAK: 32 +// Set up first user process. +void +userinit(void) +{ + struct proc *p; + extern char _binary_initcode_start[], _binary_initcode_end[]; + uint _binary_initcode_size; + + _binary_initcode_size = (uint)_binary_initcode_end - (uint)_binary_initcode_start; + p = allocproc(); +//cprintf("after allocproc: initcode start: %x end %x\n", _binary_initcode_start, _binary_initcode_end); + initproc = p; +//cprintf("initproc is %x\n", initproc); + if((p->pgdir = setupkvm()) == 0) + panic("userinit: out of memory?"); +//cprintf("after setupkvm\n"); + inituvm(p->pgdir, _binary_initcode_start, _binary_initcode_size); +//cprintf("after initkvm\n"); + p->sz = PGSIZE; + memset(p->tf, 0, sizeof(*p->tf)); + p->tf->spsr = 0x10; + p->tf->sp = PGSIZE; + p->tf->pc = 0; // beginning of initcode.S + + safestrcpy(p->name, "initcode", sizeof(p->name)); + p->cwd = namei("/"); + + p->state = RUNNABLE; +} + +// Grow current process's memory by n bytes. +// Return 0 on success, -1 on failure. +int +growproc(int n) +{ + uint sz; + + sz = curr_proc->sz; + if(n > 0){ + if((sz = allocuvm(curr_proc->pgdir, sz, sz + n)) == 0) + return -1; + } else if(n < 0){ + if((sz = deallocuvm(curr_proc->pgdir, sz, sz + n)) == 0) + return -1; + } + curr_proc->sz = sz; + switchuvm(curr_proc); + return 0; +} + +// 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. +int +fork(void) +{ + int i, pid; + struct proc *np; + + // Allocate process. + if((np = allocproc()) == 0) + return -1; + + // Copy process state from p. + if((np->pgdir = copyuvm(curr_proc->pgdir, curr_proc->sz)) == 0){ + kfree(np->kstack); + np->kstack = 0; + np->state = UNUSED; + return -1; + } + np->sz = curr_proc->sz; + np->parent = curr_proc; + *np->tf = *curr_proc->tf; + + // Clear r0 so that fork returns 0 in the child. + np->tf->r0 = 0; + + for(i = 0; i < NOFILE; i++) + if(curr_proc->ofile[i]) + np->ofile[i] = filedup(curr_proc->ofile[i]); + np->cwd = idup(curr_proc->cwd); + + pid = np->pid; + np->state = RUNNABLE; + safestrcpy(np->name, curr_proc->name, sizeof(curr_proc->name)); + return pid; +} + +// 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. +void +exit(void) +{ + struct proc *p; + int fd; + + if(curr_proc == initproc) + panic("init exiting"); + + // Close all open files. + for(fd = 0; fd < NOFILE; fd++){ + if(curr_proc->ofile[fd]){ + fileclose(curr_proc->ofile[fd]); + curr_proc->ofile[fd] = 0; + } + } + + iput(curr_proc->cwd); + curr_proc->cwd = 0; + + acquire(&ptable.lock); + + // Parent might be sleeping in wait(). + wakeup1(curr_proc->parent); + + // Pass abandoned children to init. + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ + if(p->parent == curr_proc){ + p->parent = initproc; + if(p->state == ZOMBIE) + wakeup1(initproc); + } + } + + // Jump into the scheduler, never to return. + curr_proc->state = ZOMBIE; + sched(); + panic("zombie exit"); +} + +// Wait for a child process to exit and return its pid. +// Return -1 if this process has no children. +int +wait(void) +{ + struct proc *p; + int havekids, pid; + + acquire(&ptable.lock); + for(;;){ + // Scan through table looking for zombie children. + havekids = 0; + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ + if(p->parent != curr_proc) + continue; + havekids = 1; + if(p->state == ZOMBIE){ + // Found one. + pid = p->pid; + kfree(p->kstack); + p->kstack = 0; + freevm(p->pgdir); + p->state = UNUSED; + p->pid = 0; + p->parent = 0; + p->name[0] = 0; + p->killed = 0; + release(&ptable.lock); + return pid; + } + } + + // No point waiting if we don't have any children. + if(!havekids || curr_proc->killed){ + release(&ptable.lock); + return -1; + } +//cprintf("inside wait before calling sleep\n"); + // Wait for children to exit. (See wakeup1 call in proc_exit.) + sleep(curr_proc, &ptable.lock); //DOC: wait-sleep + } +} + +//PAGEBREAK: 42 +// Per-CPU process scheduler. +// Each CPU calls scheduler() after setting itself up. +// Scheduler never returns. It loops, doing: +// - choose a process to run +// - swtch to start running that process +// - eventually that process transfers control +// via swtch back to the scheduler. +void +scheduler(void) +{ + struct proc *p; + + for(;;){ + // Enable interrupts on this processor. + //cprintf("before enabling interrupts\n"); + if(first_sched) first_sched = 0; + else sti(); + + // Loop over process table looking for process to run. + acquire(&ptable.lock); + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ + if(p->state != RUNNABLE) + continue; + + // Switch to chosen process. It is the process's job + // to release ptable.lock and then reacquire it + // before jumping back to us. + curr_proc = p; +//cprintf("before switching page table\n"); + switchuvm(p); + p->state = RUNNING; +//cprintf("after switching page table\n"); + + swtch(&curr_cpu->scheduler, curr_proc->context); + + switchkvm(); + + // Process is done running for now. + // It should have changed its p->state before coming back. + curr_proc = 0; + } + release(&ptable.lock); + + } +} + +// Enter scheduler. Must hold only ptable.lock +// and have changed proc->state. +void +sched(void) +{ + int intena; + + if(!holding(&ptable.lock)) + panic("sched ptable.lock"); + if(curr_cpu->ncli != 1) + panic("sched locks"); + if(curr_proc->state == RUNNING) + panic("sched running"); + if(!(readcpsr()&PSR_DISABLE_IRQ)) + panic("sched interruptible"); + intena = curr_cpu->intena; + swtch(&curr_proc->context, curr_cpu->scheduler); + curr_cpu->intena = intena; +} + +// Give up the CPU for one scheduling round. +void +yield(void) +{ + acquire(&ptable.lock); //DOC: yieldlock + curr_proc->state = RUNNABLE; + sched(); + release(&ptable.lock); +} + +// A fork child's very first scheduling by scheduler() +// will swtch here. "Return" to user space. +void +forkret(void) +{ + static int first = 1; + // Still holding ptable.lock from scheduler. + release(&ptable.lock); + + 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; + initlog(); + } +//cprintf("inside forkret\n"); + + // Return to "caller", actually trapret (see allocproc). +} + +// Atomically release lock and sleep on chan. +// Reacquires lock when awakened. +void +sleep(void *chan, struct spinlock *lk) +{ + if(curr_proc == 0) + panic("sleep"); + + if(lk == 0) + panic("sleep without lk"); + + // Must acquire ptable.lock in order to + // change p->state and then call sched. + // Once we hold ptable.lock, we can be + // guaranteed that we won't miss any wakeup + // (wakeup runs with ptable.lock locked), + // so it's okay to release lk. + if(lk != &ptable.lock){ //DOC: sleeplock0 + acquire(&ptable.lock); //DOC: sleeplock1 + release(lk); + } + + // Go to sleep. + curr_proc->chan = chan; + curr_proc->state = SLEEPING; +//cprintf("inside sleep before calling sched\n"); + sched(); + + // Tidy up. + curr_proc->chan = 0; + + // Reacquire original lock. + if(lk != &ptable.lock){ //DOC: sleeplock2 + release(&ptable.lock); + acquire(lk); + } +} + +//PAGEBREAK! +// Wake up all processes sleeping on chan. +// The ptable lock must be held. +static void +wakeup1(void *chan) +{ + struct proc *p; + + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) + if(p->state == SLEEPING && p->chan == chan) + p->state = RUNNABLE; +} + +// Wake up all processes sleeping on chan. +void +wakeup(void *chan) +{ + acquire(&ptable.lock); + wakeup1(chan); + release(&ptable.lock); +} + +// Kill the process with the given pid. +// Process won't exit until it returns +// to user space (see trap in trap.c). +int +kill(int pid) +{ + struct proc *p; + + acquire(&ptable.lock); + for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ + if(p->pid == pid){ + p->killed = 1; + // Wake process from sleep if necessary. + if(p->state == SLEEPING) + p->state = RUNNABLE; + release(&ptable.lock); + return 0; + } + } + release(&ptable.lock); + return -1; +} + +//PAGEBREAK: 36 +// Print a process listing to console. For debugging. +// Runs when user types ^P on console. +// No lock to avoid wedging a stuck machine further. +void +procdump(void) +{ +} + +