interrupts could be recursive since lapic_eoi() called before rti
so fast interrupts overflow the kernel stack fix: cli() before lapic_eoi()
This commit is contained in:
parent
8a8be1b8c3
commit
5be0039ce9
16 changed files with 194 additions and 28 deletions
75
Notes
75
Notes
|
@ -279,3 +279,78 @@ BUT now userfs doesn't do the final cat README
|
||||||
|
|
||||||
AND w/ cprintf("kbd overflow"), panic holding locks in scheduler
|
AND w/ cprintf("kbd overflow"), panic holding locks in scheduler
|
||||||
maybe also simulataneous panic("interrupt while holding a lock")
|
maybe also simulataneous panic("interrupt while holding a lock")
|
||||||
|
|
||||||
|
again (holding down x key):
|
||||||
|
kbd overflow
|
||||||
|
kbd oaaniicloowh
|
||||||
|
olding locks in scheduler
|
||||||
|
trap v 33 eip 100F5F c^CNext at t=32166285
|
||||||
|
(0) [0x0010033e] 0008:0010033e (unk. ctxt): jmp .+0xfffffffe (0x0010033e) ; ebfe
|
||||||
|
(1) [0x0010005c] 0008:0010005c (unk. ctxt): jmp .+0xfffffffe (0x0010005c) ; ebfe
|
||||||
|
cpu0 paniced due to holding locks in scheduler
|
||||||
|
cpu1 got panic("interrupt while holding a lock")
|
||||||
|
again in lapic_write.
|
||||||
|
while re-enabling an IRQ?
|
||||||
|
|
||||||
|
again:
|
||||||
|
cpu 0 panic("holding locks in scheduler")
|
||||||
|
but didn't trigger related panics earlier in scheduler or sched()
|
||||||
|
of course the panic is right after release() and thus sti()
|
||||||
|
so we may be seeing an interrupt that left locks held
|
||||||
|
cpu 1 unknown panic
|
||||||
|
why does it happen to both cpus at the same time?
|
||||||
|
|
||||||
|
again:
|
||||||
|
cpu 0 panic("holding locks in scheduler")
|
||||||
|
but trap() didn't see any held locks on return
|
||||||
|
cpu 1 no apparent panic
|
||||||
|
|
||||||
|
again:
|
||||||
|
cpu 0 panic: holding too many locks in scheduler
|
||||||
|
cpu 1 panic: kbd_intr returned while holding a lock
|
||||||
|
|
||||||
|
again:
|
||||||
|
cpu 0 panic: holding too man
|
||||||
|
la 10d70c lr 10027b
|
||||||
|
those don't seem to be locks...
|
||||||
|
only place non-constant lock is used is sleep()'s 2nd arg
|
||||||
|
maybe register not preserved across context switch?
|
||||||
|
it's in %esi...
|
||||||
|
sched() doesn't touch %esi
|
||||||
|
%esi is evidently callee-saved
|
||||||
|
something to do with interrupts? since ordinarily it works
|
||||||
|
cpu 1 panic: kbd_int returned while holding a lock
|
||||||
|
la 107340 lr 107300
|
||||||
|
console_lock and kbd_lock
|
||||||
|
|
||||||
|
maybe console_lock is often not released due to change
|
||||||
|
in use_console_lock (panic on other cpu)
|
||||||
|
|
||||||
|
again:
|
||||||
|
cpu 0: panic: h...
|
||||||
|
la 10D78C lr 102CA0
|
||||||
|
cpu 1: panic: acquire FL_IF (later than cpu 0)
|
||||||
|
|
||||||
|
but if sleep() were acquiring random locks, we'd see panics
|
||||||
|
in release, after sleep() returned.
|
||||||
|
actually when system is idle, maybe no-one sleeps at all.
|
||||||
|
just scheduler() and interrupts
|
||||||
|
|
||||||
|
questions:
|
||||||
|
does userfs use pipes? or fork?
|
||||||
|
no
|
||||||
|
does anything bad happen if process 1 exits? eg exit() in cat.c
|
||||||
|
looks ok
|
||||||
|
are there really no processes left?
|
||||||
|
lock_init() so we can have a magic number?
|
||||||
|
|
||||||
|
HMM maybe the variables at the end of struct cpu are being overwritten
|
||||||
|
nlocks, lastacquire, lastrelease
|
||||||
|
by cpu->stack?
|
||||||
|
adding junk buffers maybe causes crash to take longer...
|
||||||
|
when do we run on cpu stack?
|
||||||
|
just in scheduler()?
|
||||||
|
and interrupts from scheduler()
|
||||||
|
|
||||||
|
OH! recursive interrupts will use up any amount of cpu[].stack!
|
||||||
|
underflow and wrecks *previous* cpu's struct
|
||||||
|
|
8
bio.c
8
bio.c
|
@ -8,7 +8,13 @@
|
||||||
#include "buf.h"
|
#include "buf.h"
|
||||||
|
|
||||||
struct buf buf[NBUF];
|
struct buf buf[NBUF];
|
||||||
struct spinlock buf_table_lock = { "buf_table" };
|
struct spinlock buf_table_lock;
|
||||||
|
|
||||||
|
void
|
||||||
|
binit(void)
|
||||||
|
{
|
||||||
|
initlock(&buf_table_lock, "buf_table");
|
||||||
|
}
|
||||||
|
|
||||||
struct buf *
|
struct buf *
|
||||||
getblk()
|
getblk()
|
||||||
|
|
31
console.c
31
console.c
|
@ -3,11 +3,16 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
#include "dev.h"
|
#include "dev.h"
|
||||||
|
#include "param.h"
|
||||||
|
|
||||||
struct spinlock console_lock = { "console" };
|
struct spinlock console_lock;
|
||||||
int panicked = 0;
|
int panicked = 0;
|
||||||
int use_console_lock = 0;
|
int use_console_lock = 0;
|
||||||
|
|
||||||
|
// per-cpu copy of output to help panic/lock debugging
|
||||||
|
char obuf[NCPU][1024];
|
||||||
|
uint obufi[NCPU];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy console output to parallel port, which you can tell
|
* copy console output to parallel port, which you can tell
|
||||||
* .bochsrc to copy to the stdout:
|
* .bochsrc to copy to the stdout:
|
||||||
|
@ -32,6 +37,10 @@ cons_putc(int c)
|
||||||
ushort *crt = (ushort *) 0xB8000; // base of CGA memory
|
ushort *crt = (ushort *) 0xB8000; // base of CGA memory
|
||||||
int ind;
|
int ind;
|
||||||
|
|
||||||
|
obuf[rcr4()][obufi[rcr4()]++] = c;
|
||||||
|
if(obufi[rcr4()] >= 1024)
|
||||||
|
obufi[rcr4()] = 0;
|
||||||
|
|
||||||
if(panicked){
|
if(panicked){
|
||||||
cli();
|
cli();
|
||||||
for(;;)
|
for(;;)
|
||||||
|
@ -101,11 +110,13 @@ printint(int xx, int base, int sgn)
|
||||||
void
|
void
|
||||||
cprintf(char *fmt, ...)
|
cprintf(char *fmt, ...)
|
||||||
{
|
{
|
||||||
int i, state = 0, c;
|
int i, state = 0, c, locking = 0;
|
||||||
uint *ap = (uint *)(void*)&fmt + 1;
|
uint *ap = (uint *)(void*)&fmt + 1;
|
||||||
|
|
||||||
if(use_console_lock)
|
if(use_console_lock){
|
||||||
|
locking = 1;
|
||||||
acquire(&console_lock);
|
acquire(&console_lock);
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; fmt[i]; i++){
|
for(i = 0; fmt[i]; i++){
|
||||||
c = fmt[i] & 0xff;
|
c = fmt[i] & 0xff;
|
||||||
|
@ -140,7 +151,7 @@ cprintf(char *fmt, ...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(use_console_lock)
|
if(locking)
|
||||||
release(&console_lock);
|
release(&console_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +304,7 @@ static uchar *charcode[4] = {
|
||||||
char kbd_buf[KBD_BUF];
|
char kbd_buf[KBD_BUF];
|
||||||
int kbd_r;
|
int kbd_r;
|
||||||
int kbd_w;
|
int kbd_w;
|
||||||
struct spinlock kbd_lock = { "kbd_lock" };
|
struct spinlock kbd_lock;
|
||||||
|
|
||||||
void
|
void
|
||||||
kbd_intr()
|
kbd_intr()
|
||||||
|
@ -303,20 +314,17 @@ kbd_intr()
|
||||||
|
|
||||||
st = inb(KBSTATP);
|
st = inb(KBSTATP);
|
||||||
if ((st & KBS_DIB) == 0){
|
if ((st & KBS_DIB) == 0){
|
||||||
lapic_eoi();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data = inb(KBDATAP);
|
data = inb(KBDATAP);
|
||||||
|
|
||||||
if (data == 0xE0) {
|
if (data == 0xE0) {
|
||||||
shift |= E0ESC;
|
shift |= E0ESC;
|
||||||
lapic_eoi();
|
|
||||||
return;
|
return;
|
||||||
} else if (data & 0x80) {
|
} else if (data & 0x80) {
|
||||||
// Key released
|
// Key released
|
||||||
data = (shift & E0ESC ? data : data & 0x7F);
|
data = (shift & E0ESC ? data : data & 0x7F);
|
||||||
shift &= ~(shiftcode[data] | E0ESC);
|
shift &= ~(shiftcode[data] | E0ESC);
|
||||||
lapic_eoi();
|
|
||||||
return;
|
return;
|
||||||
} else if (shift & E0ESC) {
|
} else if (shift & E0ESC) {
|
||||||
// Last character was an E0 escape; or with 0x80
|
// Last character was an E0 escape; or with 0x80
|
||||||
|
@ -346,14 +354,17 @@ kbd_intr()
|
||||||
}
|
}
|
||||||
|
|
||||||
release(&kbd_lock);
|
release(&kbd_lock);
|
||||||
|
|
||||||
lapic_eoi();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
console_init()
|
console_init()
|
||||||
{
|
{
|
||||||
|
initlock(&console_lock, "console");
|
||||||
|
initlock(&kbd_lock, "kbd");
|
||||||
|
|
||||||
devsw[CONSOLE].d_write = console_write;
|
devsw[CONSOLE].d_write = console_write;
|
||||||
|
|
||||||
ioapic_enable (IRQ_KBD, 1);
|
ioapic_enable (IRQ_KBD, 1);
|
||||||
|
|
||||||
|
use_console_lock = 1;
|
||||||
}
|
}
|
||||||
|
|
5
defs.h
5
defs.h
|
@ -10,6 +10,7 @@ void panic(char *s);
|
||||||
void kbd_intr(void);
|
void kbd_intr(void);
|
||||||
|
|
||||||
// proc.c
|
// proc.c
|
||||||
|
void pinit(void);
|
||||||
struct proc;
|
struct proc;
|
||||||
struct jmpbuf;
|
struct jmpbuf;
|
||||||
void setupsegs(struct proc *);
|
void setupsegs(struct proc *);
|
||||||
|
@ -67,6 +68,7 @@ void ioapic_enable (int irq, int cpu);
|
||||||
|
|
||||||
// spinlock.c
|
// spinlock.c
|
||||||
struct spinlock;
|
struct spinlock;
|
||||||
|
void initlock(struct spinlock *, char *);
|
||||||
void acquire(struct spinlock*);
|
void acquire(struct spinlock*);
|
||||||
void release(struct spinlock*);
|
void release(struct spinlock*);
|
||||||
int holding(struct spinlock*);
|
int holding(struct spinlock*);
|
||||||
|
@ -83,6 +85,7 @@ int pipe_write(struct pipe *p, char *addr, int n);
|
||||||
int pipe_read(struct pipe *p, char *addr, int n);
|
int pipe_read(struct pipe *p, char *addr, int n);
|
||||||
|
|
||||||
// fd.c
|
// fd.c
|
||||||
|
void fd_init(void);
|
||||||
int fd_ualloc(void);
|
int fd_ualloc(void);
|
||||||
struct fd * fd_alloc(void);
|
struct fd * fd_alloc(void);
|
||||||
void fd_close(struct fd *);
|
void fd_close(struct fd *);
|
||||||
|
@ -97,6 +100,7 @@ void* ide_start_rw(int diskno, uint secno, void *dst, uint nsecs, int read);
|
||||||
int ide_finish(void *);
|
int ide_finish(void *);
|
||||||
|
|
||||||
// bio.c
|
// bio.c
|
||||||
|
void binit(void);
|
||||||
struct buf;
|
struct buf;
|
||||||
struct buf *getblk(void);
|
struct buf *getblk(void);
|
||||||
struct buf *bread(uint, uint);
|
struct buf *bread(uint, uint);
|
||||||
|
@ -104,6 +108,7 @@ void bwrite(uint, struct buf *, uint);
|
||||||
void brelse(struct buf *);
|
void brelse(struct buf *);
|
||||||
|
|
||||||
// fs.c
|
// fs.c
|
||||||
|
void iinit(void);
|
||||||
struct inode * iget(uint dev, uint inum);
|
struct inode * iget(uint dev, uint inum);
|
||||||
void ilock(struct inode *ip);
|
void ilock(struct inode *ip);
|
||||||
void iunlock(struct inode *ip);
|
void iunlock(struct inode *ip);
|
||||||
|
|
6
fd.c
6
fd.c
|
@ -13,6 +13,12 @@ struct devsw devsw[NDEV];
|
||||||
|
|
||||||
struct fd fds[NFD];
|
struct fd fds[NFD];
|
||||||
|
|
||||||
|
void
|
||||||
|
fd_init(void)
|
||||||
|
{
|
||||||
|
initlock(&fd_table_lock, "fd_table");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate a file descriptor number for curproc.
|
* allocate a file descriptor number for curproc.
|
||||||
*/
|
*/
|
||||||
|
|
8
fs.c
8
fs.c
|
@ -13,10 +13,16 @@
|
||||||
// these are inodes currently in use
|
// these are inodes currently in use
|
||||||
// an entry is free if count == 0
|
// an entry is free if count == 0
|
||||||
struct inode inode[NINODE];
|
struct inode inode[NINODE];
|
||||||
struct spinlock inode_table_lock = { "inode_table" };
|
struct spinlock inode_table_lock;
|
||||||
|
|
||||||
uint rootdev = 1;
|
uint rootdev = 1;
|
||||||
|
|
||||||
|
void
|
||||||
|
iinit(void)
|
||||||
|
{
|
||||||
|
initlock(&inode_table_lock, "inode_table");
|
||||||
|
}
|
||||||
|
|
||||||
static uint
|
static uint
|
||||||
balloc(uint dev)
|
balloc(uint dev)
|
||||||
{
|
{
|
||||||
|
|
4
ide.c
4
ide.c
|
@ -26,7 +26,7 @@ struct ide_request {
|
||||||
};
|
};
|
||||||
struct ide_request request[NREQUEST];
|
struct ide_request request[NREQUEST];
|
||||||
int head, tail;
|
int head, tail;
|
||||||
struct spinlock ide_lock = { "ide" };
|
struct spinlock ide_lock;
|
||||||
|
|
||||||
int disk_channel;
|
int disk_channel;
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ ide_wait_ready(int check_error)
|
||||||
void
|
void
|
||||||
ide_init(void)
|
ide_init(void)
|
||||||
{
|
{
|
||||||
|
initlock(&ide_lock, "ide");
|
||||||
if (ncpu < 2) {
|
if (ncpu < 2) {
|
||||||
panic ("ide_init: disk interrupt is going to the second cpu\n");
|
panic ("ide_init: disk interrupt is going to the second cpu\n");
|
||||||
}
|
}
|
||||||
|
@ -61,7 +62,6 @@ ide_intr(void)
|
||||||
// cprintf("cpu%d: ide_intr\n", cpu());
|
// cprintf("cpu%d: ide_intr\n", cpu());
|
||||||
wakeup(&request[tail]);
|
wakeup(&request[tail]);
|
||||||
release(&ide_lock);
|
release(&ide_lock);
|
||||||
lapic_eoi();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
3
kalloc.c
3
kalloc.c
|
@ -15,7 +15,7 @@
|
||||||
#include "proc.h"
|
#include "proc.h"
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
|
|
||||||
struct spinlock kalloc_lock = { "kalloc" };
|
struct spinlock kalloc_lock;
|
||||||
|
|
||||||
struct run {
|
struct run {
|
||||||
struct run *next;
|
struct run *next;
|
||||||
|
@ -37,6 +37,7 @@ kinit(void)
|
||||||
uint mem;
|
uint mem;
|
||||||
char *start;
|
char *start;
|
||||||
|
|
||||||
|
initlock(&kalloc_lock, "kalloc");
|
||||||
start = (char *) &end;
|
start = (char *) &end;
|
||||||
start = (char *) (((uint)start + PAGE) & ~(PAGE-1));
|
start = (char *) (((uint)start + PAGE) & ~(PAGE-1));
|
||||||
mem = 256; // XXX
|
mem = 256; // XXX
|
||||||
|
|
18
main.c
18
main.c
|
@ -15,8 +15,6 @@ extern uchar _binary_user1_start[], _binary_user1_size[];
|
||||||
extern uchar _binary_usertests_start[], _binary_usertests_size[];
|
extern uchar _binary_usertests_start[], _binary_usertests_size[];
|
||||||
extern uchar _binary_userfs_start[], _binary_userfs_size[];
|
extern uchar _binary_userfs_start[], _binary_userfs_size[];
|
||||||
|
|
||||||
extern int use_console_lock;
|
|
||||||
|
|
||||||
// CPU 0 starts running C code here.
|
// CPU 0 starts running C code here.
|
||||||
// This is called main0 not main so that it can have
|
// This is called main0 not main so that it can have
|
||||||
// a void return type. Gcc can't handle functions named
|
// a void return type. Gcc can't handle functions named
|
||||||
|
@ -27,28 +25,36 @@ main0(void)
|
||||||
int i;
|
int i;
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
|
|
||||||
|
lcr4(0); // xxx copy of cpu #
|
||||||
|
|
||||||
// clear BSS
|
// clear BSS
|
||||||
memset(edata, 0, end - edata);
|
memset(edata, 0, end - edata);
|
||||||
|
|
||||||
// Make sure interrupts stay disabled on all processors
|
// Make sure interrupts stay disabled on all processors
|
||||||
// until each signals it is ready, by pretending to hold
|
// until each signals it is ready, by pretending to hold
|
||||||
// an extra lock.
|
// an extra lock.
|
||||||
for(i=0; i<NCPU; i++)
|
// xxx maybe replace w/ acquire remembering if FL_IF
|
||||||
|
for(i=0; i<NCPU; i++){
|
||||||
cpus[i].nlock++;
|
cpus[i].nlock++;
|
||||||
|
cpus[i].guard1 = 0xdeadbeef;
|
||||||
|
cpus[i].guard2 = 0xdeadbeef;
|
||||||
|
}
|
||||||
|
|
||||||
mp_init(); // collect info about this machine
|
mp_init(); // collect info about this machine
|
||||||
|
|
||||||
use_console_lock = 1;
|
|
||||||
|
|
||||||
lapic_init(mp_bcpu());
|
lapic_init(mp_bcpu());
|
||||||
|
|
||||||
cprintf("\n\ncpu%d: booting xv6\n\n", cpu());
|
cprintf("\n\ncpu%d: booting xv6\n\n", cpu());
|
||||||
|
|
||||||
|
pinit();
|
||||||
|
binit();
|
||||||
pic_init(); // initialize PIC
|
pic_init(); // initialize PIC
|
||||||
ioapic_init();
|
ioapic_init();
|
||||||
kinit(); // physical memory allocator
|
kinit(); // physical memory allocator
|
||||||
tvinit(); // trap vectors
|
tvinit(); // trap vectors
|
||||||
idtinit(); // this CPU's idt register
|
idtinit(); // this CPU's idt register
|
||||||
|
fd_init();
|
||||||
|
iinit();
|
||||||
|
|
||||||
// create a fake process per CPU
|
// create a fake process per CPU
|
||||||
// so each CPU always has a tss and a gdt
|
// so each CPU always has a tss and a gdt
|
||||||
|
@ -101,6 +107,8 @@ main0(void)
|
||||||
void
|
void
|
||||||
mpmain(void)
|
mpmain(void)
|
||||||
{
|
{
|
||||||
|
lcr4(1); // xxx copy of cpu #
|
||||||
|
|
||||||
cprintf("cpu%d: starting\n", cpu());
|
cprintf("cpu%d: starting\n", cpu());
|
||||||
idtinit(); // CPU's idt
|
idtinit(); // CPU's idt
|
||||||
if(cpu() == 0)
|
if(cpu() == 0)
|
||||||
|
|
1
mmu.h
1
mmu.h
|
@ -178,6 +178,7 @@ struct gatedesc {
|
||||||
|
|
||||||
// Set up a normal interrupt/trap gate descriptor.
|
// Set up a normal interrupt/trap gate descriptor.
|
||||||
// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
|
// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
|
||||||
|
// interrupt gate clears FL_IF, trap gate leaves FL_IF alone
|
||||||
// - sel: Code segment selector for interrupt/trap handler
|
// - sel: Code segment selector for interrupt/trap handler
|
||||||
// - off: Offset in code segment for interrupt/trap handler
|
// - off: Offset in code segment for interrupt/trap handler
|
||||||
// - dpl: Descriptor Privilege Level -
|
// - dpl: Descriptor Privilege Level -
|
||||||
|
|
2
pipe.c
2
pipe.c
|
@ -34,7 +34,7 @@ pipe_alloc(struct fd **fd1, struct fd **fd2)
|
||||||
p->writeopen = 1;
|
p->writeopen = 1;
|
||||||
p->writep = 0;
|
p->writep = 0;
|
||||||
p->readp = 0;
|
p->readp = 0;
|
||||||
memset(&p->lock, 0, sizeof(p->lock));
|
initlock(&p->lock, "pipe");
|
||||||
(*fd1)->type = FD_PIPE;
|
(*fd1)->type = FD_PIPE;
|
||||||
(*fd1)->readable = 1;
|
(*fd1)->readable = 1;
|
||||||
(*fd1)->writeable = 0;
|
(*fd1)->writeable = 0;
|
||||||
|
|
16
proc.c
16
proc.c
|
@ -7,7 +7,7 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "spinlock.h"
|
#include "spinlock.h"
|
||||||
|
|
||||||
struct spinlock proc_table_lock = { "proc_table" };
|
struct spinlock proc_table_lock;
|
||||||
|
|
||||||
struct proc proc[NPROC];
|
struct proc proc[NPROC];
|
||||||
struct proc *curproc[NCPU];
|
struct proc *curproc[NCPU];
|
||||||
|
@ -15,6 +15,12 @@ int next_pid = NCPU;
|
||||||
extern void forkret(void);
|
extern void forkret(void);
|
||||||
extern void forkret1(struct trapframe*);
|
extern void forkret1(struct trapframe*);
|
||||||
|
|
||||||
|
void
|
||||||
|
pinit(void)
|
||||||
|
{
|
||||||
|
initlock(&proc_table_lock, "proc_table");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up a process's task state and segment descriptors
|
* set up a process's task state and segment descriptors
|
||||||
* correctly, given its current size and address in memory.
|
* correctly, given its current size and address in memory.
|
||||||
|
@ -146,6 +152,9 @@ scheduler(void)
|
||||||
// Loop over process table looking for process to run.
|
// Loop over process table looking for process to run.
|
||||||
acquire(&proc_table_lock);
|
acquire(&proc_table_lock);
|
||||||
for(i = 0; i < NPROC; i++){
|
for(i = 0; i < NPROC; i++){
|
||||||
|
if(cpus[cpu()].guard1 != 0xdeadbeef ||
|
||||||
|
cpus[cpu()].guard2 != 0xdeadbeef)
|
||||||
|
panic("cpu guard");
|
||||||
p = &proc[i];
|
p = &proc[i];
|
||||||
if(p->state != RUNNABLE)
|
if(p->state != RUNNABLE)
|
||||||
continue;
|
continue;
|
||||||
|
@ -194,6 +203,7 @@ scheduler(void)
|
||||||
|
|
||||||
// XXX if not holding proc_table_lock panic.
|
// XXX if not holding proc_table_lock panic.
|
||||||
}
|
}
|
||||||
|
|
||||||
release(&proc_table_lock);
|
release(&proc_table_lock);
|
||||||
|
|
||||||
if(cpus[cpu()].nlock != 0)
|
if(cpus[cpu()].nlock != 0)
|
||||||
|
@ -212,7 +222,9 @@ scheduler(void)
|
||||||
void
|
void
|
||||||
sched(void)
|
sched(void)
|
||||||
{
|
{
|
||||||
if(setjmp(&curproc[cpu()]->jmpbuf) == 0)
|
struct proc *p = curproc[cpu()];
|
||||||
|
|
||||||
|
if(setjmp(&p->jmpbuf) == 0)
|
||||||
longjmp(&cpus[cpu()].jmpbuf);
|
longjmp(&cpus[cpu()].jmpbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
proc.h
4
proc.h
|
@ -41,8 +41,6 @@ struct proc{
|
||||||
uint sz; // total size of mem, including kernel stack
|
uint sz; // total size of mem, including kernel stack
|
||||||
char *kstack; // kernel stack, separate from mem so it doesn't move
|
char *kstack; // kernel stack, separate from mem so it doesn't move
|
||||||
enum proc_state state;
|
enum proc_state state;
|
||||||
enum proc_state newstate; // desired state after swtch()
|
|
||||||
struct spinlock *mtx; // mutex for condition variable
|
|
||||||
int pid;
|
int pid;
|
||||||
int ppid;
|
int ppid;
|
||||||
void *chan; // sleep
|
void *chan; // sleep
|
||||||
|
@ -68,7 +66,9 @@ extern struct proc *curproc[NCPU]; // can be NULL if no proc running.
|
||||||
struct cpu {
|
struct cpu {
|
||||||
uchar apicid; // Local APIC ID
|
uchar apicid; // Local APIC ID
|
||||||
struct jmpbuf jmpbuf;
|
struct jmpbuf jmpbuf;
|
||||||
|
int guard1;
|
||||||
char mpstack[MPSTACK]; // per-cpu start-up stack
|
char mpstack[MPSTACK]; // per-cpu start-up stack
|
||||||
|
int guard2;
|
||||||
volatile int booted;
|
volatile int booted;
|
||||||
int nlock; // # of locks currently held
|
int nlock; // # of locks currently held
|
||||||
struct spinlock *lastacquire; // xxx debug
|
struct spinlock *lastacquire; // xxx debug
|
||||||
|
|
18
spinlock.c
18
spinlock.c
|
@ -10,8 +10,19 @@
|
||||||
// because cprintf uses them itself.
|
// because cprintf uses them itself.
|
||||||
//#define cprintf dont_use_cprintf
|
//#define cprintf dont_use_cprintf
|
||||||
|
|
||||||
|
#define LOCKMAGIC 0x6673ffea
|
||||||
|
|
||||||
extern int use_console_lock;
|
extern int use_console_lock;
|
||||||
|
|
||||||
|
void
|
||||||
|
initlock(struct spinlock *lock, char *name)
|
||||||
|
{
|
||||||
|
lock->magic = LOCKMAGIC;
|
||||||
|
lock->name = name;
|
||||||
|
lock->locked = 0;
|
||||||
|
lock->cpu = 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
getcallerpcs(void *v, uint pcs[])
|
getcallerpcs(void *v, uint pcs[])
|
||||||
{
|
{
|
||||||
|
@ -27,6 +38,8 @@ getcallerpcs(void *v, uint pcs[])
|
||||||
void
|
void
|
||||||
acquire(struct spinlock * lock)
|
acquire(struct spinlock * lock)
|
||||||
{
|
{
|
||||||
|
if(lock->magic != LOCKMAGIC)
|
||||||
|
panic("weird lock magic");
|
||||||
if(holding(lock))
|
if(holding(lock))
|
||||||
panic("acquire");
|
panic("acquire");
|
||||||
|
|
||||||
|
@ -45,6 +58,9 @@ acquire(struct spinlock * lock)
|
||||||
void
|
void
|
||||||
release(struct spinlock * lock)
|
release(struct spinlock * lock)
|
||||||
{
|
{
|
||||||
|
if(lock->magic != LOCKMAGIC)
|
||||||
|
panic("weird lock magic");
|
||||||
|
|
||||||
if(!holding(lock))
|
if(!holding(lock))
|
||||||
panic("release");
|
panic("release");
|
||||||
|
|
||||||
|
@ -55,8 +71,6 @@ release(struct spinlock * lock)
|
||||||
lock->locked = 0;
|
lock->locked = 0;
|
||||||
if(--cpus[cpu()].nlock == 0)
|
if(--cpus[cpu()].nlock == 0)
|
||||||
sti();
|
sti();
|
||||||
// xxx we may have just turned interrupts on during
|
|
||||||
// an interrupt, is that ok?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
struct spinlock {
|
struct spinlock {
|
||||||
|
uint magic;
|
||||||
char *name;
|
char *name;
|
||||||
uint locked;
|
uint locked;
|
||||||
uint pcs[10];
|
|
||||||
int cpu;
|
int cpu;
|
||||||
|
uint pcs[10];
|
||||||
};
|
};
|
||||||
|
|
20
trap.c
20
trap.c
|
@ -41,6 +41,17 @@ trap(struct trapframe *tf)
|
||||||
panic("interrupt while holding a lock");
|
panic("interrupt while holding a lock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(cpu() == 1 && curproc[cpu()] == 0){
|
||||||
|
if(&tf < cpus[cpu()].mpstack || &tf > cpus[cpu()].mpstack + 512){
|
||||||
|
cprintf("&tf %x mpstack %x\n", &tf, cpus[cpu()].mpstack);
|
||||||
|
panic("trap cpu stack");
|
||||||
|
}
|
||||||
|
} else if(curproc[cpu()]){
|
||||||
|
if(&tf < curproc[cpu()]->kstack){
|
||||||
|
panic("trap kstack");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(v == T_SYSCALL){
|
if(v == T_SYSCALL){
|
||||||
struct proc *cp = curproc[cpu()];
|
struct proc *cp = curproc[cpu()];
|
||||||
int num = cp->tf->eax;
|
int num = cp->tf->eax;
|
||||||
|
@ -97,11 +108,20 @@ trap(struct trapframe *tf)
|
||||||
|
|
||||||
if(v == (IRQ_OFFSET + IRQ_IDE)){
|
if(v == (IRQ_OFFSET + IRQ_IDE)){
|
||||||
ide_intr();
|
ide_intr();
|
||||||
|
if(cpus[cpu()].nlock)
|
||||||
|
panic("ide_intr returned while holding a lock");
|
||||||
|
cli(); // prevent a waiting interrupt from overflowing stack
|
||||||
|
lapic_eoi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(v == (IRQ_OFFSET + IRQ_KBD)){
|
if(v == (IRQ_OFFSET + IRQ_KBD)){
|
||||||
kbd_intr();
|
kbd_intr();
|
||||||
|
if(cpus[cpu()].nlock){
|
||||||
|
panic("kbd_intr returned while holding a lock");
|
||||||
|
}
|
||||||
|
cli(); // prevent a waiting interrupt from overflowing stack
|
||||||
|
lapic_eoi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue