]> Devi Nivas Git - cs3210-lab0.git/commitdiff
fix race in holding() check in acquire()
authorrtm <rtm>
Tue, 8 Aug 2006 19:58:06 +0000 (19:58 +0000)
committerrtm <rtm>
Tue, 8 Aug 2006 19:58:06 +0000 (19:58 +0000)
give cpu1 a TSS and gdt for when it enters scheduler()
and a pseudo proc[] entry for each cpu
cpu0 waits for each other cpu to start up
read() for files

20 files changed:
Makefile
Notes
README [new file with mode: 0644]
cat.c [new file with mode: 0644]
echo.c
fd.c
fd.h
ide.c
ioapic.c
lapic.c
main.c
mp.c
proc.c
proc.h
spinlock.c
spinlock.h
syscall.c
trap.c
user.h
userfs.c

index c0153add465e6cd6eb167d49f2c78599ac82acac..cc83f3e23ecb152cc919f247d8fdd57130e848e5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -71,6 +71,10 @@ echo : echo.o $(ULIB)
        $(LD) -N -e main -Ttext 0 -o echo echo.o $(ULIB)
        $(OBJDUMP) -S echo > echo.asm
 
+cat : cat.o $(ULIB)
+       $(LD) -N -e main -Ttext 0 -o cat cat.o $(ULIB)
+       $(OBJDUMP) -S cat > cat.asm
+
 userfs : userfs.o $(ULIB)
        $(LD) -N -e main -Ttext 0 -o userfs userfs.o $(ULIB)
        $(OBJDUMP) -S userfs > userfs.asm
@@ -78,8 +82,8 @@ userfs : userfs.o $(ULIB)
 mkfs : mkfs.c fs.h
        cc -o mkfs mkfs.c
 
-fs.img : mkfs usertests echo
-       ./mkfs fs.img usertests echo
+fs.img : mkfs usertests echo cat README
+       ./mkfs fs.img usertests echo cat README
 
 -include *.d
 
diff --git a/Notes b/Notes
index 22658fcd68912fc5e2d97733ee4e7d6cba87bc56..2291621dafbceb339342e55b1d9ec063d8bf4570 100644 (file)
--- a/Notes
+++ b/Notes
@@ -163,3 +163,81 @@ and file arguments longer than 14
 and directories longer than one sector
 
 kalloc() can return 0; do callers handle this right?
+
+why directing interrupts to cpu 1 causes trouble
+  cpu 1 turns on interrupts with no tss!
+    and perhaps a stale gdt (from boot)
+  since it has never run a process, never called setupsegs()
+  but does cpu really need the tss?
+    not switching stacks
+  fake process per cpu, just for tss?
+    seems like a waste
+  move tss to cpu[]?
+    but tss points to per-process kernel stack
+    would also give us a gdt
+  OOPS that wasn't the problem
+
+wait for other cpu to finish starting before enabling interrupts?
+  some kind of crash in ide_init ioapic_enable cprintf
+move ide_init before mp_start?
+  didn't do any good
+  maybe cpu0 taking ide interrupt, cpu1 getting a nested lock error
+
+cprintfs are screwed up if locking is off
+  often loops forever
+  hah, just use lpt alone
+
+looks like cpu0 took the ide interrupt and was the last to hold
+the lock, but cpu1 thinks it is nested
+cpu0 is in load_icode / printf / cons_putc
+  probably b/c cpu1 cleared use_console_lock
+cpu1 is in scheduler() / printf / acquire
+
+  1: init timer
+  0: init timer
+  cpu 1 initial nlock 1
+  ne0s:t iidd el_occnkt rc
+  onsole cpu 1 old caller stack 1001A5 10071D 104DFF 1049FE
+  panic: acquire
+  ^CNext at t=33002418
+  (0) [0x00100091] 0008:0x00100091 (unk. ctxt): jmp .+0xfffffffe          ; ebfe
+  (1) [0x00100332] 0008:0x00100332 (unk. ctxt): jmp .+0xfffffffe          
+  
+why is output interleaved even before panic?
+
+does release turn on interrupts even inside an interrupt handler?
+
+overflowing cpu[] stack?
+  probably not, change from 512 to 4096 didn't do anything
+
+
+  1: init timer
+  0: init timer
+  cnpeus te11  linnitki aclo nnoolleek  cp1u
+   ss  oarltd  sccahleldeul esrt aocnk  cpu 0111 Ej6  buf1 01A3140 C5118 
+  0
+  la anic1::7 0a0c0  uuirr e
+  ^CNext at t=31691050
+  (0) [0x00100373] 0008:0x00100373 (unk. ctxt): jmp .+0xfffffffe          ; ebfe
+  (1) [0x00100091] 0008:0x00100091 (unk. ctxt): jmp .+0xfffffffe          ; ebfe
+
+cpu0:
+
+0: init timer
+nested lock console cpu 0 old caller stack 1001e6 101a34 1 0
+  (that's mpmain)
+panic: acquire
+
+cpu1:
+
+1: init timer
+cpu 1 initial nlock 1
+start scheduler on cpu 1 jmpbuf ...
+la 107000 lr ...
+  that is, nlock != 0
+
+maybe a race; acquire does
+  locked = 1
+  cpu = cpu()
+what if another acquire calls holding w/ locked = 1 but
+  before cpu is set?
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..ce0bbfb
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This is the content of file README.
diff --git a/cat.c b/cat.c
new file mode 100644 (file)
index 0000000..8154ae2
--- /dev/null
+++ b/cat.c
@@ -0,0 +1,35 @@
+#include "user.h"
+
+char buf[513];
+
+int
+main(int argc, char *argv[])
+{
+  int fd, i, cc;
+
+  if(argc < 2){
+    puts("Usage: cat files...\n");
+    exit();
+  }
+
+  for(i = 1; i < argc; i++){
+    fd = open(argv[i], 0);
+    if(fd < 0){
+      puts("cat: cannot open ");
+      puts(argv[i]);
+      puts("\n");
+      exit();
+    }
+    while((cc = read(fd, buf, sizeof(buf) - 1)) > 0){
+      buf[cc] = '\0';
+      puts(buf);
+    }
+    if(cc < 0){
+      puts("cat: read error\n");
+      exit();
+    }
+    close(fd);
+  }
+
+  exit();
+}
diff --git a/echo.c b/echo.c
index 89e19a925cb3b18969a27489571dc8d1a818f454..5d0c5a488e71787fcdae2a90e0e74305ea0b8cb8 100644 (file)
--- a/echo.c
+++ b/echo.c
@@ -5,7 +5,7 @@ main(int argc, char *argv[])
 {
   int i;
 
-  for(i = 0; i < argc; i++){
+  for(i = 1; i < argc; i++){
     puts(argv[i]);
     puts(" ");
   }
diff --git a/fd.c b/fd.c
index 9ce6bae5a8a49ce4e6770dcbac3ac4e8916d7630..8332454fab5bdde0a8609eca45906e16684da99c 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -69,6 +69,13 @@ fd_read(struct fd *fd, char *addr, int n)
     return -1;
   if(fd->type == FD_PIPE){
     return pipe_read(fd->pipe, addr, n);
+  } else if(fd->type == FD_FILE){
+    ilock(fd->ip);
+    int cc = readi(fd->ip, addr, fd->off, n);
+    if(cc > 0)
+      fd->off += cc;
+    iunlock(fd->ip);
+    return cc;
   } else {
     panic("fd_read");
     return -1;
diff --git a/fd.h b/fd.h
index 442ee343d83bf45db12b34b3639f870a10c12781..1be1cf09bb54701e6b777b91650b0311c3140773 100644 (file)
--- a/fd.h
+++ b/fd.h
@@ -5,6 +5,7 @@ struct fd {
   char writeable;
   struct pipe *pipe;
   struct inode *ip;
+  uint off;
 };
 
 extern struct fd fds[NFD];
diff --git a/ide.c b/ide.c
index d6bef6d1e74f43d3097b17bec3676a3da3b4c678..af509fcfeaead10413b0c92a9c443482d57eb2c0 100644 (file)
--- a/ide.c
+++ b/ide.c
@@ -51,14 +51,14 @@ ide_init(void)
   }
   ioapic_enable (14, 1); // 14 is IRQ # for IDE
   ide_wait_ready(0);
-  cprintf ("ide_init:done\n");
+  cprintf ("cpu%d: ide_init:done\n", cpu());
 }
 
 void
 ide_intr(void)
 {
   acquire(&ide_lock);
-  cprintf("%d: ide_intr\n", cpu());
+  cprintf("cpu%d: ide_intr\n", cpu());
   wakeup(&request[tail]);
   release(&ide_lock);
   lapic_eoi();
index 776f8958ae7d1a35a68ea8968b90e1dec405aded..b926863b4539023ad3587608b0e115a0f89ceeee 100644 (file)
--- a/ioapic.c
+++ b/ioapic.c
@@ -65,7 +65,7 @@ ioapic_init(void)
 }
 
 void
-ioapic_enable (int irq, int cpu)
+ioapic_enable (int irq, int cpunum)
 {
   uint l, h;
   struct ioapic *io;
@@ -76,7 +76,7 @@ ioapic_enable (int irq, int cpu)
   ioapic_write(io, IOAPIC_REDTBL_LO(irq), l);
   h = ioapic_read(io, IOAPIC_REDTBL_HI(irq));
   h &= ~IOART_DEST;
-  h |= (cpu << APIC_ID_SHIFT);  // for fun, disk interrupts to cpu 1
+  h |= (cpunum << APIC_ID_SHIFT);  // for fun, disk interrupts to cpu 1
   ioapic_write(io, IOAPIC_REDTBL_HI(irq), h);
-  cprintf("intr %d: lo 0x%x hi 0x%x\n", irq, l, h);
+  cprintf("cpu%d: intr %d: lo 0x%x hi 0x%x\n", cpu(), irq, l, h);
 }
diff --git a/lapic.c b/lapic.c
index f299b86d99a5e90e0ee82f5fb9f7ee569f43ee0e..161d0a52d70ac313197c1ed73f86ea7e6a0d221e 100644 (file)
--- a/lapic.c
+++ b/lapic.c
@@ -110,7 +110,7 @@ lapic_write(int r, int data)
 void
 lapic_timerinit(void)
 {
-  cprintf("%d: init timer\n", cpu());
+  cprintf("cpu%d: init timer\n", cpu());
   lapic_write(LAPIC_TDCR, LAPIC_X1);
   lapic_write(LAPIC_TIMER, LAPIC_CLKIN | LAPIC_PERIODIC | (IRQ_OFFSET + IRQ_TIMER));
   lapic_write(LAPIC_TCCR, 10000000);
@@ -120,7 +120,7 @@ lapic_timerinit(void)
 void
 lapic_timerintr(void)
 {
-  cprintf("%d: timer interrupt!\n", cpu());
+  cprintf("cpu%d: timer interrupt!\n", cpu());
   lapic_write (LAPIC_EOI, 0);
 }
 
@@ -129,7 +129,7 @@ lapic_init(int c)
 {
   uint r, lvt;
 
-  cprintf("lapic_init %d\n", c);
+  cprintf("cpu%d: lapic_init %d\n", c);
 
   lapic_write(LAPIC_DFR, 0xFFFFFFFF); // set destination format register
   r = (lapic_read(LAPIC_ID)>>24) & 0xFF; // read APIC ID
@@ -158,7 +158,7 @@ lapic_init(int c)
   while(lapic_read(LAPIC_ICRLO) & APIC_DELIVS)
     ;
 
-  cprintf("Done init of an apic\n");
+  cprintf("cpu%d: apic init done\n", cpu());
 }
 
 void
@@ -182,7 +182,8 @@ lapic_eoi(void)
 int
 cpu(void)
 {
-  return (lapic_read(LAPIC_ID)>>24) & 0xFF;
+  int x = (lapic_read(LAPIC_ID)>>24) & 0xFF;
+  return x;
 }
 
 void
diff --git a/main.c b/main.c
index 021fb51bfae71df6196001076d569a38dd1dc7d7..c6e27a534d14a52dbe6ce3f304c1b449e388aa29 100644 (file)
--- a/main.c
+++ b/main.c
@@ -42,18 +42,24 @@ main0(void)
 
   lapic_init(mp_bcpu());
 
-  cprintf("\nxV6\n\n");
+  cprintf("\n\ncpu%d: booting xv6\n\n", cpu());
 
   pic_init(); // initialize PIC
   ioapic_init();
   kinit(); // physical memory allocator
   tvinit(); // trap vectors
-  idtinit(); // CPU's idt
+  idtinit(); // this CPU's idt register
+
+  // create a fake process per CPU
+  // so each CPU always has a tss and a gdt
+  for(p = &proc[0]; p < &proc[NCPU]; p++){
+    p->state = IDLEPROC;
+    p->kstack = cpus[p-proc].mpstack;
+    p->pid = p - proc;
+  }
 
-  // create fake process zero
+  // fix process 0 so that copyproc() will work
   p = &proc[0];
-  memset(p, 0, sizeof *p);
-  p->state = SLEEPING;
   p->sz = 4 * PAGE;
   p->mem = kalloc(p->sz);
   memset(p->mem, 0, p->sz);
@@ -63,20 +69,20 @@ main0(void)
   p->tf->es = p->tf->ds = p->tf->ss = (SEG_UDATA << 3) | 3;
   p->tf->cs = (SEG_UCODE << 3) | 3;
   p->tf->eflags = FL_IF;
-  p->pid = 0;
-  p->ppid = 0;
   setupsegs(p);
 
+  // init disk device
+  ide_init(); 
+
   mp_startthem();
 
   // turn on timer and enable interrupts on the local APIC
   lapic_timerinit();
   lapic_enableintr();
 
-  // init disk device
-  ide_init(); 
-
   // Enable interrupts on this processor.
+  cprintf("cpu%d: nlock %d before -- and sti\n",
+          cpu(), cpus[0].nlock);
   cpus[cpu()].nlock--;
   sti();
 
@@ -94,7 +100,7 @@ main0(void)
 void
 mpmain(void)
 {
-  cprintf("an application processor\n");
+  cprintf("cpu%d: starting\n", cpu());
   idtinit(); // CPU's idt
   if(cpu() == 0)
     panic("mpmain on cpu 0");
@@ -102,8 +108,13 @@ mpmain(void)
   lapic_timerinit();
   lapic_enableintr();
 
+  setupsegs(&proc[cpu()]);
+
+  cpuid(0, 0, 0, 0, 0);        // memory barrier
+  cpus[cpu()].booted = 1;
+
   // Enable interrupts on this processor.
-  cprintf("cpu %d initial nlock %d\n", cpu(), cpus[cpu()].nlock);
+  cprintf("cpu%d: initial nlock %d\n", cpu(), cpus[cpu()].nlock);
   cpus[cpu()].nlock--;
   sti();
 
diff --git a/mp.c b/mp.c
index ece46a4f4c0aa5aaa2cf8603b257536d8251e8ff..341b5452771d3b7f8623c06fb3a2f8145b0ea4b0 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -219,9 +219,11 @@ mp_startthem(void)
 
   for(c = 0; c < ncpu; c++){
     if (c == cpu()) continue;
-    cprintf ("starting processor %d\n", c);
+    cprintf ("cpu%d: starting processor %d\n", cpu(), c);
     *(uint *)(APBOOTCODE-4) = (uint) (cpus[c].mpstack) + MPSTACK; // tell it what to use for %esp
     *(uint *)(APBOOTCODE-8) = (uint)mpmain; // tell it where to jump to
     lapic_startap(cpus[c].apicid, (uint) APBOOTCODE);
+    while(cpus[c].booted == 0)
+      ;
   }
 }
diff --git a/proc.c b/proc.c
index b67810e9221e1706abf542977236886d7656877e..0254c2ec22f490dcf3034e0d9a354dd0ecc312f7 100644 (file)
--- a/proc.c
+++ b/proc.c
@@ -11,7 +11,7 @@ struct spinlock proc_table_lock = { "proc_table" };
 
 struct proc proc[NPROC];
 struct proc *curproc[NCPU];
-int next_pid = 1;
+int next_pid = NCPU;
 extern void forkret(void);
 extern void forkret1(struct trapframe*);
 
@@ -31,7 +31,7 @@ setupsegs(struct proc *p)
   // XXX it may be wrong to modify the current segment table!
 
   p->gdt[0] = SEG_NULL;
-  p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0);
+  p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0x100000 + 64*1024, 0); // xxx
   p->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0);
   p->gdt[SEG_TSS] = SEG16(STS_T32A, (uint) &p->ts,
                                 sizeof(p->ts), 0);
@@ -134,8 +134,8 @@ scheduler(void)
   struct proc *p;
   int i;
 
-  cprintf("start scheduler on cpu %d jmpbuf %p\n", cpu(), &cpus[cpu()].jmpbuf);
-  cpus[cpu()].lastproc = &proc[0];
+  cprintf("cpu%d: start scheduler jmpbuf %p\n",
+          cpu(), &cpus[cpu()].jmpbuf);
 
   if(cpus[cpu()].nlock != 0){
     cprintf("la %x lr %x\n", cpus[cpu()].lastacquire, cpus[cpu()].lastrelease   );
@@ -190,6 +190,8 @@ scheduler(void)
         panic("scheduler lock");
       }
 
+      setupsegs(&proc[cpu()]);
+
       // XXX if not holding proc_table_lock panic.
     }
     release(&proc_table_lock);
diff --git a/proc.h b/proc.h
index a27314113c7320dc96e0935c0b8bb01fa03e8ac6..c6f5be67f983f352cfe90d909e15ba2d276cab8e 100644 (file)
--- a/proc.h
+++ b/proc.h
@@ -33,7 +33,8 @@ struct jmpbuf {
   int eip;
 };
 
-enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
+enum proc_state { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE,
+                  IDLEPROC };
 
 struct proc{
   char *mem; // start of process's physical memory
@@ -67,8 +68,8 @@ extern struct proc *curproc[NCPU];  // can be NULL if no proc running.
 struct cpu {
   uchar apicid;       // Local APIC ID
   struct jmpbuf jmpbuf;
-  char mpstack[MPSTACK]; // per-cpu start-up stack, only used to get into main()
-  struct proc *lastproc;  // last proc scheduled on this cpu (never NULL)
+  char mpstack[MPSTACK]; // per-cpu start-up stack
+  volatile int booted;
   int nlock; // # of locks currently held
   struct spinlock *lastacquire; // xxx debug
   struct spinlock *lastrelease; // xxx debug
index bde6e461815ef63f998d0f4c6631c5331c57bc92..5a0fd23e69e633f5ebb5c9fdb12659b8f664ea7d 100644 (file)
 
 extern int use_console_lock;
 
-int
-getcallerpc(void *v)
+void
+getcallerpcs(void *v, uint pcs[])
 {
-       return ((int*)v)[-1];
+  uint *ebp = (uint*)v - 2;
+  int i;
+  for(i = 0; i < 10 && ebp && ebp != (uint*)0xffffffff; ebp = (uint*)*ebp, i++){
+    pcs[i] = *(ebp + 1);
+  }
+  for( ; i < 10; i++)
+    pcs[i] = 0;
 }
 
 void
 acquire(struct spinlock * lock)
 {
-  if(holding(lock)){
-    extern use_console_lock;
-    use_console_lock = 0;
-    cprintf("lock %s pc %x\n", lock->name ? lock->name : "", lock->pc);
-               panic("acquire");
-  }
+  if(holding(lock))
+    panic("acquire");
 
        if(cpus[cpu()].nlock++ == 0)
                cli();
        while(cmpxchg(0, 1, &lock->locked) == 1)
                ;
        cpuid(0, 0, 0, 0, 0);   // memory barrier
-       lock->pc = getcallerpc(&lock);
-       lock->cpu = cpu();
+       getcallerpcs(&lock, lock->pcs);
+       lock->cpu = cpu() + 10;
         cpus[cpu()].lastacquire = lock;
 }
 
@@ -45,6 +47,8 @@ release(struct spinlock * lock)
                panic("release");
 
         cpus[cpu()].lastrelease = lock;
+        lock->pcs[0] = 0;
+        lock->cpu = 0xffffffff;
        cpuid(0, 0, 0, 0, 0);   // memory barrier
        lock->locked = 0;
        if(--cpus[cpu()].nlock == 0)
@@ -54,5 +58,5 @@ release(struct spinlock * lock)
 int
 holding(struct spinlock *lock)
 {
-       return lock->locked && lock->cpu == cpu();
+       return lock->locked && lock->cpu == cpu() + 10;
 }
index ee48a7e2620ba7787cad917d148dc655ccbd3df9..f866b4c918b3cce1df06e26570ee1b23677b1c02 100644 (file)
@@ -1,6 +1,6 @@
 struct spinlock {
   char *name;
   uint locked;
-  uint pc;
+  uint pcs[10];
   int cpu;
 };
index 498078e111d342d283271a5ab7a9676fb82e65fc..ce6e22d0b22da25dfcf5c6919145343830063a37 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -274,6 +274,7 @@ sys_open(void)
   fd->readable = 1;
   fd->writeable = 0;
   fd->ip = ip;
+  fd->off = 0;
   cp->fds[ufd] = fd;
 
   return ufd;
diff --git a/trap.c b/trap.c
index ccbc75482a9ff9db2832a34d3153c32498a8ea51..70312238e4729434962c0a66206889af9969400e 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -34,6 +34,14 @@ void
 trap(struct trapframe *tf)
 {
   int v = tf->trapno;
+  
+  if(cpus[cpu()].nlock){
+    cprintf("trap v %d eip %x cpu %d nlock %d\n",
+            v, tf->eip, cpu(), cpus[cpu()].nlock);
+    panic("interrupt while holding a lock");
+  }
+  if((read_eflags() & FL_IF) == 0)
+    panic("interrupt but interrupts now disabled");
 
   if(v == T_SYSCALL){
     struct proc *cp = curproc[cpu()];
@@ -61,16 +69,13 @@ trap(struct trapframe *tf)
       panic("trap ret esp wrong");
     if(cp->killed)
       proc_exit();
+    // XXX probably ought to lgdt on trap return
     return;
   }
 
   if(v == (IRQ_OFFSET + IRQ_TIMER)){
     struct proc *cp = curproc[cpu()];
     lapic_timerintr();
-    if(cpus[cpu()].nlock)
-      panic("timer interrupt while holding a lock");
-    if((read_eflags() & FL_IF) == 0)
-      panic("timer interrupt but interrupts now disabled");
     if(cp){
       // Force process exit if it has been killed
       // and the interrupt came from user space.
@@ -92,8 +97,5 @@ trap(struct trapframe *tf)
     return;
   }
 
-
-  // XXX probably ought to lgdt on trap return
-
   return;
 }
diff --git a/user.h b/user.h
index cf9881672c64e494bd91adc86642e511352ea1b5..d86933845d83b434f14f486bb036f0f96f2b6d90 100644 (file)
--- a/user.h
+++ b/user.h
@@ -10,6 +10,8 @@ int block(void);
 int kill(int);
 int panic(char*);
 int cons_puts(char*);
+int exec(char *, char **);
+int open(char *, int);
 int mknod (char*,short,short,short);
 int puts(char*);
 int puts1(char*);
index 0b2e9c31ca3419abad3ec58c17d2ffc1ce16f2a9..b11f3ebb7ec266f5c1b9977b3f0acb4811af4351 100644 (file)
--- a/userfs.c
+++ b/userfs.c
@@ -5,7 +5,8 @@
 // file system tests
 
 char buf[1024];
-char *args[] = { "echo", "hello", "goodbye", 0 };
+char *echo_args[] = { "echo", "hello", "goodbye", 0 };
+char *cat_args[] = { "cat", "README", 0 };
 
 int
 main(void)
@@ -34,6 +35,7 @@ main(void)
   } else {
     puts("open doesnotexist failed\n");
   }
-  exec("echo", args);
+  //exec("echo", echo_args);
+  exec("cat", cat_args);
   return 0;
 }