summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/exec.c5
-rw-r--r--kernel/fs.c2
-rw-r--r--kernel/pipe.c2
-rw-r--r--kernel/proc.c250
-rw-r--r--kernel/proc.h3
-rw-r--r--kernel/riscv.h9
-rw-r--r--kernel/sleeplock.c2
-rw-r--r--kernel/spinlock.h2
-rw-r--r--kernel/stat.h4
-rw-r--r--kernel/syscall.c3
-rw-r--r--kernel/sysfile.c2
-rw-r--r--kernel/sysproc.c1
-rw-r--r--kernel/trap.c2
-rw-r--r--kernel/uart.c2
-rw-r--r--runoff.list2
-rw-r--r--user/ls.c2
-rw-r--r--user/printf.c2
17 files changed, 177 insertions, 118 deletions
diff --git a/kernel/exec.c b/kernel/exec.c
index c9af395..b21afbb 100644
--- a/kernel/exec.c
+++ b/kernel/exec.c
@@ -2,6 +2,7 @@
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
+#include "spinlock.h"
#include "proc.h"
#include "defs.h"
#include "elf.h"
@@ -19,7 +20,6 @@ exec(char *path, char **argv)
struct proghdr ph;
pagetable_t pagetable = 0, oldpagetable;
struct proc *p = myproc();
- uint64 oldsz = p->sz;
begin_op();
@@ -60,6 +60,9 @@ exec(char *path, char **argv)
end_op();
ip = 0;
+ p = myproc();
+ uint64 oldsz = p->sz;
+
// Allocate two pages at the next page boundary.
// Use the second as the user stack.
sz = PGROUNDUP(sz);
diff --git a/kernel/fs.c b/kernel/fs.c
index ebd8f7a..c241b3c 100644
--- a/kernel/fs.c
+++ b/kernel/fs.c
@@ -14,8 +14,8 @@
#include "defs.h"
#include "param.h"
#include "stat.h"
-#include "proc.h"
#include "spinlock.h"
+#include "proc.h"
#include "sleeplock.h"
#include "fs.h"
#include "buf.h"
diff --git a/kernel/pipe.c b/kernel/pipe.c
index 31bf0cc..eca5959 100644
--- a/kernel/pipe.c
+++ b/kernel/pipe.c
@@ -2,9 +2,9 @@
#include "riscv.h"
#include "defs.h"
#include "param.h"
+#include "spinlock.h"
#include "proc.h"
#include "fs.h"
-#include "spinlock.h"
#include "sleeplock.h"
#include "file.h"
diff --git a/kernel/proc.c b/kernel/proc.c
index 20d5085..a947f7f 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -2,33 +2,36 @@
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
-#include "proc.h"
#include "spinlock.h"
+#include "proc.h"
#include "defs.h"
-struct {
- struct spinlock lock;
- struct proc proc[NPROC];
-} ptable;
+struct proc proc[NPROC];
struct cpu cpus[NCPU];
struct proc *initproc;
+struct spinlock pid_lock;
int nextpid = 1;
+
extern void forkret(void);
// for returning out of the kernel
extern void sysexit(void);
-static void wakeup1(void *chan);
+static void wakeup1(struct proc *chan);
extern char trampout[]; // trampoline.S
void
procinit(void)
{
- initlock(&ptable.lock, "ptable");
+ struct proc *p;
+
+ initlock(&pid_lock, "nextpid");
+ for(p = proc; p < &proc[NPROC]; p++)
+ initlock(&p->lock, "proc");
}
// Must be called with interrupts disabled,
@@ -60,40 +63,48 @@ myproc(void) {
return p;
}
+int
+allocpid() {
+ int pid;
+
+ acquire(&pid_lock);
+ pid = nextpid++;
+ release(&pid_lock);
+ return pid;
+}
+
//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.
+// If found, initialize state required to run in the kernel,
+// and return with p->lock held.
// Otherwise return 0.
static struct proc*
allocproc(void)
{
struct proc *p;
- acquire(&ptable.lock);
-
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
- if(p->state == UNUSED)
+ for(p = proc; p < &proc[NPROC]; p++) {
+ acquire(&p->lock);
+ if(p->state == UNUSED) {
goto found;
-
- release(&ptable.lock);
+ } else {
+ release(&p->lock);
+ }
+ }
return 0;
found:
- p->state = EMBRYO;
- p->pid = nextpid++;
-
- release(&ptable.lock);
+ p->pid = allocpid();
// Allocate a page for the kernel stack.
if((p->kstack = kalloc()) == 0){
- p->state = UNUSED;
return 0;
}
// Allocate a trapframe page.
if((p->tf = (struct trapframe *)kalloc()) == 0){
- p->state = UNUSED;
+ kfree(p->kstack);
+ p->kstack = 0;
return 0;
}
@@ -111,7 +122,7 @@ found:
// free a proc structure and the data hanging from it,
// including user pages.
-// the proc lock must be held.
+// p->lock must be held.
static void
freeproc(struct proc *p)
{
@@ -195,22 +206,16 @@ userinit(void)
uvminit(p->pagetable, initcode, sizeof(initcode));
p->sz = PGSIZE;
- // prepare for the very first kernel->user.
+ // prepare for the very first "return" from kernel to user.
p->tf->epc = 0;
p->tf->sp = PGSIZE;
safestrcpy(p->name, "initcode", sizeof(p->name));
p->cwd = namei("/");
- // this assignment to p->state lets other cores
- // run this process. the acquire forces the above
- // writes to be visible, and the lock is also needed
- // because the assignment might not be atomic.
- acquire(&ptable.lock);
-
p->state = RUNNABLE;
- release(&ptable.lock);
+ release(&p->lock);
}
// Grow current process's memory by n bytes.
@@ -223,11 +228,13 @@ growproc(int n)
sz = p->sz;
if(n > 0){
- if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0)
+ if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0) {
return -1;
+ }
} else if(n < 0){
- if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0)
+ if((sz = uvmdealloc(p->pagetable, sz, sz + n)) == 0) {
return -1;
+ }
}
p->sz = sz;
return 0;
@@ -250,6 +257,7 @@ fork(void)
// Copy user memory from parent to child.
if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){
freeproc(np);
+ release(&np->lock);
return -1;
}
np->sz = p->sz;
@@ -272,15 +280,39 @@ fork(void)
pid = np->pid;
- acquire(&ptable.lock);
-
np->state = RUNNABLE;
- release(&ptable.lock);
+ release(&np->lock);
return pid;
}
+// Pass p's abandoned children to init. p and p's parent
+// are locked.
+void
+reparent(struct proc *p, struct proc *parent) {
+ struct proc *pp;
+ int child_of_init = (p->parent == initproc);
+
+ for(pp = proc; pp < &proc[NPROC]; pp++){
+ if (pp != p && pp != parent) {
+ acquire(&pp->lock);
+ if(pp->parent == p){
+ pp->parent = initproc;
+ if(pp->state == ZOMBIE) {
+ if(!child_of_init)
+ acquire(&initproc->lock);
+ wakeup1(initproc);
+ if(!child_of_init)
+ release(&initproc->lock);
+ }
+ }
+ release(&pp->lock);
+ }
+ }
+}
+
+
// Exit the current process. Does not return.
// An exited process remains in the zombie state
// until its parent calls wait().
@@ -288,7 +320,6 @@ void
exit(void)
{
struct proc *p = myproc();
- struct proc *pp;
int fd;
if(p == initproc)
@@ -297,7 +328,8 @@ exit(void)
// Close all open files.
for(fd = 0; fd < NOFILE; fd++){
if(p->ofile[fd]){
- fileclose(p->ofile[fd]);
+ struct file *f = p->ofile[fd];
+ fileclose(f);
p->ofile[fd] = 0;
}
}
@@ -307,22 +339,20 @@ exit(void)
end_op();
p->cwd = 0;
- acquire(&ptable.lock);
+ acquire(&p->parent->lock);
+
+ acquire(&p->lock);
+
+ reparent(p, p->parent);
+
+ p->state = ZOMBIE;
// Parent might be sleeping in wait().
wakeup1(p->parent);
- // Pass abandoned children to init.
- for(pp = ptable.proc; pp < &ptable.proc[NPROC]; pp++){
- if(pp->parent == p){
- pp->parent = initproc;
- if(pp->state == ZOMBIE)
- wakeup1(initproc);
- }
- }
+ release(&p->parent->lock);
// Jump into the scheduler, never to return.
- p->state = ZOMBIE;
sched();
panic("zombie exit");
}
@@ -335,32 +365,35 @@ wait(void)
struct proc *np;
int havekids, pid;
struct proc *p = myproc();
-
- acquire(&ptable.lock);
+
+ acquire(&p->lock);
for(;;){
// Scan through table looking for exited children.
havekids = 0;
- for(np = ptable.proc; np < &ptable.proc[NPROC]; np++){
+ for(np = proc; np < &proc[NPROC]; np++){
if(np->parent != p)
continue;
+ acquire(&np->lock);
havekids = 1;
if(np->state == ZOMBIE){
// Found one.
pid = np->pid;
freeproc(np);
- release(&ptable.lock);
+ release(&np->lock);
+ release(&p->lock);
return pid;
}
+ release(&np->lock);
}
// No point waiting if we don't have any children.
if(!havekids || p->killed){
- release(&ptable.lock);
+ release(&p->lock);
return -1;
}
-
- // Wait for children to exit. (See wakeup1 call in proc_exit.)
- sleep(p, &ptable.lock); //DOC: wait-sleep
+
+ // Wait for children to exit. (See wakeup1 call in reparent.)
+ sleep(p, &p->lock); //DOC: wait-sleep
}
}
@@ -377,35 +410,32 @@ scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
-
+
c->proc = 0;
for(;;){
// Enable interrupts on this processor.
intr_on();
- // 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.
- c->proc = p;
- p->state = RUNNING;
-
- swtch(&c->scheduler, &p->context);
-
- // Process is done running for now.
- // It should have changed its p->state before coming back.
- c->proc = 0;
+ for(p = proc; p < &proc[NPROC]; p++) {
+ acquire(&p->lock);
+ if(p->state == RUNNABLE) {
+ // Switch to chosen process. It is the process's job
+ // to release its lock and then reacquire it
+ // before jumping back to us.
+ p->state = RUNNING;
+ c->proc = p;
+ swtch(&c->scheduler, &p->context);
+
+ // Process is done running for now.
+ // It should have changed its p->state before coming back.
+ c->proc = 0;
+ }
+ release(&p->lock);
}
- release(&ptable.lock);
}
}
-// Enter scheduler. Must hold only ptable.lock
+// Enter scheduler. Must hold only p->lock
// and have changed proc->state. Saves and restores
// intena because intena is a property of this
// kernel thread, not this CPU. It should
@@ -418,8 +448,8 @@ sched(void)
int intena;
struct proc *p = myproc();
- if(!holding(&ptable.lock))
- panic("sched ptable.lock");
+ if(!holding(&p->lock))
+ panic("sched p->lock");
if(mycpu()->noff != 1)
panic("sched locks");
if(p->state == RUNNING)
@@ -436,10 +466,11 @@ sched(void)
void
yield(void)
{
- acquire(&ptable.lock); //DOC: yieldlock
- myproc()->state = RUNNABLE;
+ struct proc *p = myproc();
+ acquire(&p->lock); //DOC: yieldlock
+ p->state = RUNNABLE;
sched();
- release(&ptable.lock);
+ release(&p->lock);
}
// A fork child's very first scheduling by scheduler()
@@ -449,8 +480,8 @@ forkret(void)
{
static int first = 1;
- // Still holding ptable.lock from scheduler.
- release(&ptable.lock);
+ // Still holding p->lock from scheduler.
+ release(&myproc()->lock);
if (first) {
// Some initialization functions must be run in the context
@@ -477,14 +508,14 @@ sleep(void *chan, struct spinlock *lk)
if(lk == 0)
panic("sleep without lk");
- // Must acquire ptable.lock in order to
+ // Must acquire p->lock in order to
// change p->state and then call sched.
- // Once we hold ptable.lock, we can be
+ // Once we hold p->lock, we can be
// guaranteed that we won't miss any wakeup
- // (wakeup runs with ptable.lock locked),
+ // (wakeup runs with p->lock locked),
// so it's okay to release lk.
- if(lk != &ptable.lock){ //DOC: sleeplock0
- acquire(&ptable.lock); //DOC: sleeplock1
+ if(lk != &p->lock){ //DOC: sleeplock0
+ acquire(&p->lock); //DOC: sleeplock1
release(lk);
}
// Go to sleep.
@@ -497,32 +528,37 @@ sleep(void *chan, struct spinlock *lk)
p->chan = 0;
// Reacquire original lock.
- if(lk != &ptable.lock){ //DOC: sleeplock2
- release(&ptable.lock);
+ if(lk != &p->lock){ //DOC: sleeplock2
+ release(&p->lock);
acquire(lk);
}
}
//PAGEBREAK!
-// Wake up all processes sleeping on chan.
-// The ptable lock must be held.
+// Wake up p, used by exit()
+// Caller should lock p.
static void
-wakeup1(void *chan)
+wakeup1(struct proc *p)
{
- struct proc *p;
-
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
- if(p->state == SLEEPING && p->chan == chan)
- p->state = RUNNABLE;
+ if(p->chan == p && p->state == SLEEPING) {
+ p->state = RUNNABLE;
+ }
}
-// Wake up all processes sleeping on chan.
+// Wake up all processes sleeping on chan. Never
+// called when holding a p->lock
void
wakeup(void *chan)
{
- acquire(&ptable.lock);
- wakeup1(chan);
- release(&ptable.lock);
+ struct proc *p;
+
+ for(p = proc; p < &proc[NPROC]; p++) {
+ acquire(&p->lock);
+ if(p->state == SLEEPING && p->chan == chan) {
+ p->state = RUNNABLE;
+ }
+ release(&p->lock);
+ }
}
// Kill the process with the given pid.
@@ -533,18 +569,19 @@ kill(int pid)
{
struct proc *p;
- acquire(&ptable.lock);
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+ for(p = proc; p < &proc[NPROC]; p++){
if(p->pid == pid){
+ acquire(&p->lock);
+ if(p->pid != pid)
+ panic("kill");
p->killed = 1;
// Wake process from sleep if necessary.
if(p->state == SLEEPING)
p->state = RUNNABLE;
- release(&ptable.lock);
+ release(&p->lock);
return 0;
}
}
- release(&ptable.lock);
return -1;
}
@@ -586,7 +623,6 @@ procdump(void)
{
static char *states[] = {
[UNUSED] "unused",
- [EMBRYO] "embryo",
[SLEEPING] "sleep ",
[RUNNABLE] "runble",
[RUNNING] "run ",
@@ -595,7 +631,7 @@ procdump(void)
struct proc *p;
char *state;
- for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
+ for(p = proc; p < &proc[NPROC]; p++){
if(p->state == UNUSED)
continue;
if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
diff --git a/kernel/proc.h b/kernel/proc.h
index 278e4cd..687fdd1 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -78,10 +78,11 @@ struct trapframe {
/* 280 */ uint64 t6;
};
-enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
+enum procstate { UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state
struct proc {
+ struct spinlock lock;
char *kstack; // Bottom of kernel stack for this process
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // Page table
diff --git a/kernel/riscv.h b/kernel/riscv.h
index c3371a4..e5c0f64 100644
--- a/kernel/riscv.h
+++ b/kernel/riscv.h
@@ -304,6 +304,15 @@ w_tp(uint64 x)
asm volatile("mv tp, %0" : : "r" (x));
}
+static inline uint64
+r_ra()
+{
+ uint64 x;
+ asm volatile("mv %0, ra" : "=r" (x) );
+ return x;
+}
+
+
#define PGSIZE 4096 // bytes per page
#define PGSHIFT 12 // bits of offset within a page
diff --git a/kernel/sleeplock.c b/kernel/sleeplock.c
index b490370..81de585 100644
--- a/kernel/sleeplock.c
+++ b/kernel/sleeplock.c
@@ -5,8 +5,8 @@
#include "defs.h"
#include "param.h"
#include "memlayout.h"
-#include "proc.h"
#include "spinlock.h"
+#include "proc.h"
#include "sleeplock.h"
void
diff --git a/kernel/spinlock.h b/kernel/spinlock.h
index 4392820..5f244c9 100644
--- a/kernel/spinlock.h
+++ b/kernel/spinlock.h
@@ -5,5 +5,7 @@ struct spinlock {
// For debugging:
char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock.
+ struct cpu *last_release;
+ uint64 last_pc;
};
diff --git a/kernel/stat.h b/kernel/stat.h
index a498321..19543af 100644
--- a/kernel/stat.h
+++ b/kernel/stat.h
@@ -3,9 +3,9 @@
#define T_DEVICE 3 // Device
struct stat {
- short type; // Type of file
int dev; // File system's disk device
uint ino; // Inode number
+ short type; // Type of file
short nlink; // Number of links to file
- uint size; // Size of file in bytes
+ uint64 size; // Size of file in bytes
};
diff --git a/kernel/syscall.c b/kernel/syscall.c
index ff10f9c..a054da2 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -2,6 +2,7 @@
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
+#include "spinlock.h"
#include "proc.h"
#include "syscall.h"
#include "defs.h"
@@ -170,7 +171,9 @@ dosyscall(void)
num = p->tf->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
+ //printf("%d: syscall %d\n", p->pid, num);
p->tf->a0 = syscalls[num]();
+ //printf("%d: syscall %d -> %d\n", p->pid, num, p->tf->a0);
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
diff --git a/kernel/sysfile.c b/kernel/sysfile.c
index 77e273f..533e097 100644
--- a/kernel/sysfile.c
+++ b/kernel/sysfile.c
@@ -9,9 +9,9 @@
#include "defs.h"
#include "param.h"
#include "stat.h"
+#include "spinlock.h"
#include "proc.h"
#include "fs.h"
-#include "spinlock.h"
#include "sleeplock.h"
#include "file.h"
#include "fcntl.h"
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index 93ea9bc..face81a 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -4,6 +4,7 @@
#include "date.h"
#include "param.h"
#include "memlayout.h"
+#include "spinlock.h"
#include "proc.h"
uint64
diff --git a/kernel/trap.c b/kernel/trap.c
index 835a3b0..018b7db 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -2,8 +2,8 @@
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
-#include "proc.h"
#include "spinlock.h"
+#include "proc.h"
#include "defs.h"
struct spinlock tickslock;
diff --git a/kernel/uart.c b/kernel/uart.c
index 35fac1b..b8dd664 100644
--- a/kernel/uart.c
+++ b/kernel/uart.c
@@ -2,8 +2,8 @@
#include "param.h"
#include "memlayout.h"
#include "riscv.h"
-#include "proc.h"
#include "spinlock.h"
+#include "proc.h"
#include "defs.h"
//
diff --git a/runoff.list b/runoff.list
index 6e6af18..f3e9224 100644
--- a/runoff.list
+++ b/runoff.list
@@ -9,6 +9,7 @@ kernel/date.h
# entering xv6
kernel/entry.S
+kernel/start.c
kernel/main.c
# locks
@@ -24,6 +25,7 @@ kernel/kalloc.c
# system calls
user/usys.pl
+kernel/kernelvec.S
kernel/trap.c
kernel/syscall.h
kernel/syscall.c
diff --git a/user/ls.c b/user/ls.c
index c649c57..3511d87 100644
--- a/user/ls.c
+++ b/user/ls.c
@@ -43,7 +43,7 @@ ls(char *path)
switch(st.type){
case T_FILE:
- printf(1, "%s %d %d %d\n", fmtname(path), st.type, st.ino, st.size);
+ printf(1, "%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size);
break;
case T_DIR:
diff --git a/user/printf.c b/user/printf.c
index 0c6b34b..f3b3282 100644
--- a/user/printf.c
+++ b/user/printf.c
@@ -68,6 +68,8 @@ printf(int fd, const char *fmt, ...)
} else if(state == '%'){
if(c == 'd'){
printint(fd, va_arg(ap, int), 10, 1);
+ } else if(c == 'l') {
+ printint(fd, va_arg(ap, uint64), 10, 0);
} else if(c == 'x') {
printint(fd, va_arg(ap, int), 16, 0);
} else if(c == 'p') {